﻿using BZ.Camera.MindVision;
using BZ.Core.TaskExt;
using BZ.Logger;
using BZVision;
using HalconDotNet;
using HslCommunication;
using NDK.Frm;
using NDK.LocalUtils;
using NDK.Module.DAL;
using NDK.Module.Model;
using NDK.Module.StationLogic;
using NDK.Motion.BLL;
using NDK.Motion.MachineManager;
using NDK.Motion.StationLogic;
using NDK.Motion.Sys;
using NDK.Utils;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
//using BoTech.Services;
using static NDK.Module.Model.Common;

namespace NDK.Module.BLL
{
    /// <summary>
    /// 公共方法类
    /// </summary>
    class PublicMethod
    {
        const int ON = 1;
        const int OFF = 0;

        #region STO功能变量定义/STO功能的轴以及对应的限制位置的定义
        public static string[] aixsName = { "R1", "R2", "Z1", "Z2", "Z3", "Z4", "Z5", "Z6", "Z7", "Z8",
                                         "X3", "X4", "X1", "Z9", "Y1", "Z10", "Y2", "Z11", "X2", "Z12",
                                         "Y3", "Z13", "Y4", "Z14", "Z15", "Z16", "X5", "Z17", "Y5", "Z18",
                                         "Y6", "Z19", "X6", "Z20"};

        public static double[] axisLimit = { 30, 30, 10, 10, 10, 10, 10, 10, 10, 10,
                                         100, 100, 100, 10, 100, 10, 100, 10, 100, 10,
                                         100, 10, 100, 10, 10, 10, 100,10,100,10,
                                         100,10,100,10};

        public static Dictionary<string, double> _dicAxisLimit = new Dictionary<string, double>();  //各个轴对应的限制位置

        public static List<string> PauseMovedAxisName = new List<string>();

        public static bool bStopByButton = false;  //按下了停止按钮后状态置为true
        public static Dictionary<string, double> AxisPausePosition = new Dictionary<string, double>();  //保存暂停时各个轴的当前坐标值
        public static bool IsOpenDoorAllow = true; //是否屏蔽了开门信号（数据库里面设置）
        public static bool isOpenDoor = false;  //是否已经打开了门
        public static bool isAxisAlarm = false;  //轴是否已经报警

        #endregion

        public static log4net.ILog m_Logger1 = log4net.LogManager.GetLogger("PublicMethod");

        /// <summary>
        /// 延时，单位ms
        /// </summary>
        /// <param name="milliSeconds"></param>
        public static void Delay (int milliSeconds)
        {
            if(milliSeconds < 10)
            {
                Thread.Sleep(milliSeconds);
            }
            else
            {
                DateTime tStop = DateTime.Now.AddMilliseconds(milliSeconds);
                while(true)
                {
                    Thread.Sleep(10);
                    if(Application.MessageLoop)
                        Application.DoEvents();

                    if(DateTime.Now > tStop)
                        break;
                }
            }
        }

        /// <summary>
        /// 对象的深度复制
        /// </summary>
        /// <param name="oringinal"></param>
        /// <returns></returns>
        public static object DeepClone (object oringinal)
        {
            using(MemoryStream memoryStream = new MemoryStream())
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter
                {
                    Context = new StreamingContext(StreamingContextStates.Clone)
                };
                binaryFormatter.Serialize(memoryStream, oringinal);
                memoryStream.Position = 0L;
                return binaryFormatter.Deserialize(memoryStream);
            }
        }

        /// <summary>
        /// 每次启动得到最新的数据
        /// </summary>
        public static void UpdateRuningData ()
        {
            Line = (string)UpdateDBData(DBType.String, "Line", Line);
            左侧工控机IP = (string)UpdateDBData(DBType.String, "左侧工控机IP", 左侧工控机IP);

            是否联机上料PLC = (bool)UpdateDBData(DBType.Bool, "是否联机上料PLC", 是否联机上料PLC);
            是否联机下料PLC = (bool)UpdateDBData(DBType.Bool, "是否联机下料PLC", 是否联机下料PLC);

            //屏蔽治具1 = (bool)UpdateDBData(DBType.Bool, "屏蔽治具1", 屏蔽治具1);
            //屏蔽治具2 = (bool)UpdateDBData(DBType.Bool, "屏蔽治具2", 屏蔽治具2);
            屏蔽扫码 = (bool)UpdateDBData(DBType.Bool, "屏蔽扫码", 屏蔽扫码);

            手动启动 = (bool)UpdateDBData(DBType.Bool, "手动启动", 手动启动);
            isShiledSafeDoor = (bool)UpdateDBData(DBType.Bool, "启用安全门", isShiledSafeDoor, true);
            isShiledSafeScreen = (bool)UpdateDBData(DBType.Bool, "启用光幕", isShiledSafeScreen, true);
            isShiedWarning = (bool)UpdateDBData(DBType.Bool, "启用蜂鸣器", isShiedWarning, true);
            isUploadMes = (bool)UpdateDBData(DBType.Bool, "上传至Mes", isUploadMes);
            isUploadApple = (bool)UpdateDBData(DBType.Bool, "上传至Apple", isUploadApple);
            //屏蔽相机采图 = (bool)UpdateDBData(DBType.Bool, "屏蔽相机采图", 屏蔽相机采图);
            //屏蔽激光扫描 = (bool)UpdateDBData(DBType.Bool, "屏蔽激光扫描", 屏蔽激光扫描);
            屏蔽左线 = (bool)UpdateDBData(DBType.Bool, "屏蔽左线", 屏蔽左线);
            屏蔽右线 = (bool)UpdateDBData(DBType.Bool, "屏蔽右线", 屏蔽右线);
            屏蔽算法 = (bool)UpdateDBData(DBType.Bool, "屏蔽算法", 屏蔽算法);


            SaveDaysOfAlarmInfo = (int)UpdateDBData(DBType.Int, "保留报警信息天数", SaveDaysOfAlarmInfo);
            GRR循环次数 = (int)UpdateDBData(DBType.Int, "GRR循环次数", GRR循环次数);
            PPG保压时间 = (int)UpdateDBData(DBType.Int, "PPG保压时间(ms)", PPG保压时间);
            气缸等待时间 = (int)UpdateDBData(DBType.Int, "气缸等待时间", 气缸等待时间);
            光源打开延时 = (int)UpdateDBData(DBType.Int, "光源打开延时", 光源打开延时);
            BarcodeLength = (int)UpdateDBData(DBType.Int, "二维码的长度", BarcodeLength);
            PPGOffset1 = (double)UpdateDBData(DBType.Double, "PPGOffset1", PPGOffset1);
            PPGOffset2 = (double)UpdateDBData(DBType.Double, "PPGOffset2", PPGOffset2);

            启用PPG = (bool)UpdateDBData(DBType.Bool, "启用PPG", 启用PPG);

            isWriteLog = (bool)UpdateDBData(DBType.Bool, "是否写log", isWriteLog);
            是否检测信号 = (bool)UpdateDBData(DBType.Bool, "是否检测信号", 是否检测信号);

            是否带料 = (bool)UpdateDBData(DBType.Bool, "是否带料", 是否带料);

            SideLaser1_SN = (string)UpdateDBData(DBType.String, "侧激光1SN", SideLaser1_SN);
            SideLaser2_SN = (string)UpdateDBData(DBType.String, "侧激光2SN", SideLaser2_SN);

            UpLaser_SN = (string)UpdateDBData(DBType.String, "上激光SN", UpLaser_SN);
            DownLaser_SN = (string)UpdateDBData(DBType.String, "下激光SN", DownLaser_SN);

            plcIP_上料机 = (string)UpdateDBData(DBType.String, "上料机PLCIP", plcIP_上料机);
            plcIP_下料机 = (string)UpdateDBData(DBType.String, "下料机PLCIP", plcIP_下料机);
            plcPort_上料机 = (string)UpdateDBData(DBType.String, "上料机PLC端口号", plcPort_上料机);
            plcPort_下料机 = (string)UpdateDBData(DBType.String, "下料机PLC端口号", plcPort_下料机);

            PPG_Name = (string)UpdateDBData(DBType.String, "PPGName", PPG_Name);

            ppgIP = (string)UpdateDBData(DBType.String, "PPGIP", ppgIP);
            PPGIP2 = (string)UpdateDBData(DBType.String, "PPGIP2", PPGIP2);

            偏移量X = (string)UpdateDBData(DBType.String, "偏移量X", 偏移量X);
            偏移量Y = (string)UpdateDBData(DBType.String, "偏移量Y", 偏移量Y);
            偏移量Theta = (string)UpdateDBData(DBType.String, "偏移量Theta", 偏移量Theta);

            IsSaveImage = (bool)UpdateDBData(DBType.Bool, "保存图片", IsSaveImage);

            屏蔽治具1 = (bool)UpdateDBData(DBType.Bool, "屏蔽治具1", 屏蔽治具1);
            屏蔽治具2 = (bool)UpdateDBData(DBType.Bool, "屏蔽治具2", 屏蔽治具2);

            启用算法补偿 = (bool)UpdateDBData(DBType.Bool, "启用算法补偿", 启用算法补偿);
            算法补偿范围下限 = (string)UpdateDBData(DBType.String, "算法补偿范围下限", 算法补偿范围下限);
            算法补偿范围上限 = (string)UpdateDBData(DBType.String, "算法补偿范围上限", 算法补偿范围上限);

            Machine.OmronPLC.Write("stPC_PLC.Spare_BOOL[0]", 屏蔽治具1);
            Machine.OmronPLC.Write("stPC_PLC.Spare_BOOL[1]", 屏蔽治具2);
            //IsSaveImage = (bool)UpdateDBData(DBType.Bool, "保存图片", IsSaveImage);
            Machine.MachineResourceInit();
            CameraServices cameraServices = new CameraServices();
            CameraParams = cameraServices.GetAllModel();
            AppendUiLog.Log("参数更新完成", LogType.Info);
        }

        public enum DBType
        {
            String, Bool, Int, Double
        }
        public static object UpdateDBData (DBType type, string ParamName, object para, bool isInverse = false)
        {
            try
            {
                switch(type)
                {
                    case DBType.String:
                        StringParamServices stringParamServices = new StringParamServices();
                        StringParam stringParam = new StringParam();

                        string paraString = (string)para;
                        stringParam = stringParamServices.GetModel($"{ParamName}");
                        if(stringParam == null)
                        {
                            stringParam = new StringParam() { ID = 0, 参数名称 = $"{ParamName}", 字符串值 = paraString };
                            stringParamServices.Add(stringParam);
                            AppendUiLog.Log($"未读取到系统变量：{ParamName},已添加默认值:{paraString}", LogType.Error);
                        }
                        else
                        {
                            paraString = stringParam.字符串值;
                        }
                        return paraString;
                    case DBType.Bool:
                        BoolParamServices boolParamServices = new BoolParamServices();
                        BoolParam boolParam = new BoolParam();

                        bool paraBool = (bool)para;
                        boolParam = boolParamServices.GetModel($"{ParamName}");
                        if(boolParam == null)
                        {
                            boolParam = new BoolParam() { ID = 0, 参数名称 = $"{ParamName}", 布尔值 = paraBool };
                            boolParamServices.Add(boolParam);
                            AppendUiLog.Log($"未读取到系统变量：{ParamName},已添加默认值:{paraBool}", LogType.Error);
                        }
                        else
                        {
                            if(!isInverse)
                                paraBool = boolParam.布尔值;
                            else
                                paraBool = !boolParam.布尔值;
                        }
                        return paraBool;
                    case DBType.Int:
                        IntParamServices intParamServices = new IntParamServices();
                        IntParam intParam = new IntParam();
                        int paraInt = (int)para;

                        intParam = intParamServices.GetModel($"{ParamName}");
                        if(intParam == null)
                        {
                            intParam = new IntParam() { ID = 0, 参数名称 = $"{ParamName}", 整型值 = paraInt, 最大值 = 999, 最小值 = -999 };
                            intParamServices.Add(intParam);
                            AppendUiLog.Log($"未读取到系统变量：{ParamName},已添加默认值:整型值:{paraInt} 最大值:999 最小值:-999", LogType.Error);
                        }
                        else
                        {
                            paraInt = intParam.整型值;
                        }
                        return paraInt;
                    case DBType.Double:
                        FloatParamServices floatParamServices = new FloatParamServices();
                        FloatParam floatParam = new FloatParam();

                        double paraDouble = (double)para;
                        floatParam = floatParamServices.GetModel($"{ParamName}");
                        if(floatParam == null)
                        {
                            floatParam = new FloatParam() { ID = 0, 参数名称 = $"{ParamName}", 浮点值 = (decimal)paraDouble, 最大值 = 999, 最小值 = -999 };
                            floatParamServices.Add(floatParam);
                            AppendUiLog.Log($"未读取到系统变量：{ParamName},已添加默认值:整型值:{paraDouble} 最大值:999 最小值:-999", LogType.Error);
                        }
                        else
                        {
                            paraDouble = (double)floatParam.浮点值;
                        }
                        return paraDouble;
                }
            }
            catch(Exception ex)
            {

            }

            return null;
        }

        public static bool OpenMes ()
        {
            #region 连接MES服务器
            isUploadMes = false;
            try
            {
                Mes mes = new Mes();

                MesServices mesServices = new MesServices();
                mes = mesServices.GetModel(1);

                XWDMesUpload uploadXWDMes = new XWDMesUpload();
                MesUrl = mes.URL;
                MesDcGroup = mes.dcgroup;
                siteId = mes.siteId;
                //登录
                Dictionary<string, string> loginResult = uploadXWDMes.login(mes.URL, mes.username, mes.password, mes.siteId, mes.operation, mes.resource);
                if(loginResult != null && loginResult.Count > 0 && loginResult["STATUS"] == "true")
                {
                    MesJession = loginResult["RESULT"];
                    AppendUiLog.Log("MES login Success!", LogType.Info);
                    //获取测试数据编号
                    Dictionary<string, string> getTestId = uploadXWDMes.getTestId(MesUrl, MesJession);
                    if(getTestId != null && getTestId.Count > 0 && getTestId["STATUS"] == "true")
                    {
                        MesTestId = getTestId["RESULT"];
                        AppendUiLog.Log("Get TestId Success", LogType.Info);
                    }
                    else
                    {
                        AppendUiLog.Log("Get TestId Fail", LogType.Error);
                    }
                    isUploadMes = true;
                    return true;
                }
                else
                {
                    AppendUiLog.Log("MES login Fail!", LogType.Error);
                }
            }
            catch(Exception ex)
            {
                m_Logger1.Error(ex.StackTrace);
            }
            return false;
            #endregion
        }

        public static void UploadMes (MeasureProduct measureProduct)
        {
            #region 上传至MES
            if(isUploadMes && !isPointCheck)
            {
                string okng = measureProduct.OK_NG;
                if(measureProduct.OK_NG == "NG")
                {
                    okng = "NG";
                }
                else if(measureProduct.OK_NG == "EXCEPTION")
                {
                    okng = "EXCEPTION";
                }
                else
                {
                    okng = "OK";
                }
                XWDMesUpload xwdMesUpload = new XWDMesUpload();
                Dictionary<string, string> checkStationResult = xwdMesUpload.checkStation(MesUrl, MesJession, measureProduct.SN);
                if(checkStationResult != null && checkStationResult.Count > 0 && checkStationResult["STATUS"] != "true")//不在当前站不上传
                {
                    string str = checkStationResult["RESULT"].ToString();
                    AppendUiLog.Log("MES Upload Fail!" + checkStationResult["RESULT"].ToString(), LogType.Error);
                    UploadMESFail = true;
                    measureProduct.NG_FAI = checkStationResult["RESULT"] + "||" + measureProduct.NG_FAI;
                    return;
                }
                string errorCode = "";
                string measureData = "{";
                if(measureProduct != null && measureProduct.MeasureData != null && measureProduct.MeasureData.Count > 0 && okng != "EXCEPTION")
                {
                    #region 
                    //全部测量信息
                    for(int j = 0; j < measureProduct.MeasureData.Count; j++)
                    {
                        #region 
                        DataItem cameraData = measureProduct.MeasureData[j];
                        string cameraDataName = cameraData.Name;
                        string faiName = string.Empty;
                        if(cameraData.Name == "AOI")
                        {
                            faiName = "FAI-AOI";
                        }
                        else if(cameraData.Name == "FAI-RANDOM-SAMPLE")
                        {
                            faiName = "FAI-RANDOM-SAMPLE";
                        }
                        else
                        {
                            faiName = "FAI-" + cameraData.Name.Substring(3);
                        }
                        cameraDataName = faiName;
                        if(cameraDataName.Contains("_"))
                        {
                            cameraDataName = cameraDataName.Replace('_', '-');
                        }
                        cameraDataName = cameraDataName.ToUpper();

                        string val = "";
                        if(cameraData.Value == 9999)
                        {
                            val = "NA";
                        }
                        else
                        {
                            val = cameraData.Value.ToString();
                        }
                        if(j == (measureProduct.MeasureData.Count - 1))
                        {
                            measureData = measureData + '"' + cameraDataName + '"' + ":" + '"' + val + '"' + "}";
                        }
                        else
                        {
                            measureData = measureData + '"' + cameraDataName + '"' + ":" + '"' + val + '"' + ",";
                        }

                        #endregion
                    }
                    Dictionary<string, string> uploadResult = xwdMesUpload.upload(MesUrl, MesJession, MesTestId, measureProduct.SN, errorCode, okng, MesDcGroup, measureData);
                    if(uploadResult != null && uploadResult.Count > 0 && uploadResult["STATUS"] != "true")
                    {
                        #region 
                        Thread.Sleep(20);
                        uploadResult = xwdMesUpload.upload(MesUrl, MesJession, MesTestId, measureProduct.SN, errorCode, okng, MesDcGroup, measureData);
                        if(uploadResult != null && uploadResult.Count > 0 && uploadResult["STATUS"] != "true")
                        {
                            Thread.Sleep(10);
                            uploadResult = xwdMesUpload.upload(MesUrl, MesJession, MesTestId, measureProduct.SN, errorCode, okng, MesDcGroup, measureData);
                            if(uploadResult != null && uploadResult.Count > 0 && uploadResult["STATUS"] != "true")
                            {
                                AppendUiLog.Log("MES Upload Fail!" + uploadResult["RESULT"].ToString(), LogType.Error);
                                UploadMESFail = true;
                            }
                            else
                            {
                                AppendUiLog.Log(measureProduct.SN + "MES Upload Success!", LogType.Info);
                            }
                        }
                        else
                        {
                            AppendUiLog.Log(measureProduct.SN + "MES Upload Success!", LogType.Info);
                        }
                        #endregion
                    }
                    else if(uploadResult != null && uploadResult.Count > 0 && uploadResult["STATUS"] == "true")
                    {
                        AppendUiLog.Log(measureProduct.SN + "MES Upload Success!", LogType.Info);

                    }

                    #endregion
                }

            }

            #endregion
        }

        #region 复位，启动，暂停状态变化
        public static void Intial ()
        {
            if(MachineStatusManager.CurrentMachineStatus == MachineStatus.Initialized)//整机复位
            {
                AppendUiLog.Log("点击复位...", LogType.Info);
                #region 检测一下是否需要屏蔽门信号
                if(!isShiledSafeDoor)
                {
                    bool? doorSgn1 = false;
                    try
                    {
                        if(Line == "ATL")
                        {
                            doorSgn1 = Machine.di_上料Tray侧门1关闭.GetStatus() || Machine.di_上料Tray侧门2关闭.GetStatus();
                        }
                        else
                        {
                            doorSgn1 = Machine.di_上料Tray侧门1关闭.GetStatus();
                        }
                        //MachineDataManager.Instance.SYS_DI_SafetyDoor?.GetStatus();
                    }
                    catch
                    {
                        AppendUiLog.Log("读取门开关IO失败！", LogType.Error);
                        return;
                    }
                    if(doorSgn1 == true)
                    {
                        AppendUiLog.Log("Check , doors are opened!", LogType.Error);
                        MessageBox.Show("Check , doors are opened!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                }
                #endregion
                MachineStatusManager.CurrentMachineStatus = MachineStatus.Homing;

                if(是否联机上料PLC && Machine.opreateResult_Isconnect.IsSuccess)
                {
                    ret_Write = Machine.OmronPLC.Write("stPC_PLC.bBt_Rest", true);
                }
                return;
            }
            else if(MachineStatusManager.CurrentMachineStatus == MachineStatus.Alarm)//报警复位
            {
                AppendUiLog.Log("点击复位...", LogType.Info);

                if(MachineStatusManager.LastMachineStatus == MachineStatus.Running)//如果报警前处于运行状态，报警复位后转到暂停状态
                {
                    MachineStatusManager.CurrentMachineStatus = MachineStatus.Pause;
                }
                else//否则恢复上次的状态
                {
                    MachineStatusManager.CurrentMachineStatus = MachineStatusManager.LastMachineStatus;
                }
                return;
            }
            else if(MachineStatusManager.CurrentMachineStatus == MachineStatus.Pause)//报警复位
            {
                AppendUiLog.Log("点击复位...", LogType.Info);

                if(MachineStatusManager.LastMachineStatus == MachineStatus.Homing)//如果报警前处于运行状态，报警复位后转到暂停状态
                {
                    MachineStatusManager.CurrentMachineStatus = MachineStatusManager.LastMachineStatus;
                }
                return;
            }
        }
        public static void Start ()
        {
            #region 检测一下是否需要屏蔽门信号
            if(!isShiledSafeDoor)
            {
                bool? doorSgn1 = false;
                try
                {
                    if(Line == "ATL")
                    {
                        if(!是否联机上料PLC)
                        {
                            doorSgn1 = Machine.di_上料操作侧门1关闭.GetStatus() || Machine.di_上料操作侧门2关闭.GetStatus() || Machine.di_上料Tray侧门1关闭.GetStatus() || Machine.di_上料Tray侧门2关闭.GetStatus() || Machine.di_下料操作侧门1关闭.GetStatus() || Machine.di_下料操作侧门2关闭.GetStatus() || Machine.di_下料操作侧门3关闭.GetStatus();

                        }
                        else
                        {
                            doorSgn1 = dic_plcComm_Bool["stPLC_PC_bSafetyDoor"] || Machine.di_上料操作侧门1关闭.GetStatus() || Machine.di_上料操作侧门2关闭.GetStatus() || Machine.di_上料Tray侧门1关闭.GetStatus() || Machine.di_上料Tray侧门2关闭.GetStatus() || Machine.di_下料操作侧门1关闭.GetStatus() || Machine.di_下料操作侧门2关闭.GetStatus() || Machine.di_下料操作侧门3关闭.GetStatus();
                        }
                    }
                    else
                    {
                        if(!是否联机上料PLC)
                        {
                            doorSgn1 = Machine.di_上料操作侧门1关闭.GetStatus() || Machine.di_上料操作侧门2关闭.GetStatus() || Machine.di_上料Tray侧门1关闭.GetStatus() || Machine.di_下料操作侧门1关闭.GetStatus() || Machine.di_下料操作侧门2关闭.GetStatus();

                        }
                        else
                        {
                            doorSgn1 = dic_plcComm_Bool["stPLC_PC_bSafetyDoor"] || Machine.di_上料操作侧门1关闭.GetStatus() || Machine.di_上料操作侧门2关闭.GetStatus() || Machine.di_上料Tray侧门1关闭.GetStatus() || Machine.di_下料操作侧门1关闭.GetStatus() || Machine.di_下料操作侧门2关闭.GetStatus();

                        }
                    }
                }
                catch
                {
                    AppendUiLog.Log("读取门开关IO失败！", LogType.Error);
                    return;
                }
                if(doorSgn1 == true)
                {
                    AppendUiLog.Log("Check , doors are opened!", LogType.Error);
                    MessageBox.Show("Check , doors are opened!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
            }
            #endregion

            #region 正常启动流程
            if((MachineStatusManager.CurrentMachineStatus == MachineStatus.Ready
                || MachineStatusManager.CurrentMachineStatus == MachineStatus.Pause)
                && MachineStatusManager.CurrentMachineStatus != MachineStatus.Running
                )
            {
                foreach(var axis in MachineDataManager.Instance.AxisList)
                {
                    axis.IsStop = false;
                }
                MachineStatusManager.CurrentMachineStatus = MachineStatus.Running;

                //Machine.do_上料操作侧门1锁定.ON();
                //Machine.do_上料操作侧门2锁定.ON();

                AppendUiLog.Log("开始运行...", LogType.Info);
            }
            #endregion

        }
        public static void Pause ()
        {
            try
            {
                if(MachineStatusManager.CurrentMachineStatus == MachineStatus.Running
                    || MachineStatusManager.CurrentMachineStatus == MachineStatus.Homing)
                {
                    AppendUiLog.Log("点击暂停...", LogType.Info);
                    MachineStatusManager.CurrentMachineStatus = MachineStatus.Pause;


                    foreach(var axis in MachineDataManager.Instance.AxisList)
                    {
                        axis.IsStop = true;
                    }

                    //Machine.do_上料操作侧门1锁定.OFF();
                    //Machine.do_上料操作侧门2锁定.OFF();
                    AppendUiLog.Log("暂停中...", LogType.Info);
                }
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.StackTrace);
            }
        }
        public static void Stop ()
        {
            if(MachineStatusManager.CurrentMachineStatus == MachineStatus.Running
                || MachineStatusManager.CurrentMachineStatus == MachineStatus.Pause
                || MachineStatusManager.CurrentMachineStatus == MachineStatus.Emerg
                || MachineStatusManager.CurrentMachineStatus == MachineStatus.Alarm
                || MachineStatusManager.CurrentMachineStatus == MachineStatus.Ready
                || MachineStatusManager.CurrentMachineStatus == MachineStatus.Homing
                )
            {
                CT.Stop();
                AppendUiLog.Log("点击停止...", LogType.Info);
                foreach(var axis in MachineDataManager.Instance.AxisList)
                {
                    axis.IsStop = true;
                }
                if(MachineStatusManager.CurrentMachineStatus == MachineStatus.Homing)//回零状态下等待停止状态回复
                {
                    foreach(var axis in MachineDataManager.Instance.AxisList)
                    {
                        while(axis.IsStop == true)
                        {
                            Thread.Sleep(100);
                        }
                    }
                }

                foreach(var axis in MachineDataManager.Instance.AxisList)//保证板卡资源释放，才能关闭工站线程，否则抛异常
                {
                    axis.WaitMoveDone();
                }
                MachineStatusManager.CurrentMachineStatus = MachineStatus.Stopping;

                //Thread.Sleep(2000);
                AppendUiLog.Log("停止中...", LogType.Info);
                StationManager.StationList.ForEach(s =>
                {
                    s?.Stop();
                });
                StationManager.StationList.Clear();
                TaskManager.StopAll();

                AppendUiLog.Log("已停止！", LogType.Alert);
                MachineStatusManager.CurrentMachineStatus = MachineStatus.Initialized;
                foreach(var axis in MachineDataManager.Instance.AxisList)
                {
                    axis.IsStop = false;
                }
            }
        }
        #endregion

        public static void PauseSafetyDoor ()
        {
            if(MachineStatusManager.CurrentMachineStatus == MachineStatus.Running
                || MachineStatusManager.CurrentMachineStatus == MachineStatus.Homing
                || MachineStatusManager.CurrentMachineStatus == MachineStatus.Ready
                || MachineStatusManager.CurrentMachineStatus == MachineStatus.Initialized)
            {
                PauseMachine();
                AppendUiLog.Log("安全门打开...", LogType.Info);
                MachineStatusManager.CurrentMachineStatus = MachineStatus.Alarm;
                AppendUiLog.Log("安全门打开...", LogType.Info);
            }
        }


        #region 三色灯控制线程函数
        public static void ThreadMethod_TriColorLamp ()
        {
            while(true)
            {
                if(isCardInitialed)
                {
                    try
                    {
                        switch(MachineStatusManager.CurrentMachineStatus)
                        {
                            case MachineStatus.Unknown://红灯闪烁
                            {
                                Machine.do_红灯.Toggle();
                                Machine.do_黄灯.OFF();
                                Machine.do_绿灯.OFF();
                                Machine.do_蜂鸣器.OFF();

                                Machine.do_启动按钮灯.OFF();
                                Machine.do_停止按钮灯.OFF();
                                Machine.do_复位按钮灯.OFF();
                            }
                            break;
                            case MachineStatus.Running://绿灯亮
                            {
                                Machine.do_红灯.OFF();
                                Machine.do_黄灯.OFF();
                                Machine.do_绿灯.ON();
                                Machine.do_蜂鸣器.OFF();

                                Machine.do_启动按钮灯.ON();
                                Machine.do_停止按钮灯.OFF();
                                Machine.do_复位按钮灯.OFF();
                            }
                            break;
                            case MachineStatus.Pause://黄灯亮
                            {
                                Machine.do_红灯.OFF();
                                Machine.do_黄灯.ON();
                                Machine.do_绿灯.OFF();
                                Machine.do_蜂鸣器.OFF();

                                Machine.do_启动按钮灯.OFF();
                                Machine.do_停止按钮灯.ON();
                                Machine.do_复位按钮灯.OFF();
                            }
                            break;
                            case MachineStatus.Initialized:
                            {
                                Machine.do_红灯.OFF();
                                Machine.do_黄灯.Toggle();
                                Machine.do_绿灯.OFF();
                                Machine.do_蜂鸣器.OFF();

                                Machine.do_启动按钮灯.OFF();
                                Machine.do_停止按钮灯.OFF();
                                Machine.do_复位按钮灯.Toggle();
                            }
                            break;
                            case MachineStatus.Homing://黄灯闪烁
                            {
                                Machine.do_红灯.OFF();
                                Machine.do_黄灯.Toggle();
                                Machine.do_绿灯.OFF();
                                Machine.do_蜂鸣器.OFF();

                                Machine.do_启动按钮灯.OFF();
                                Machine.do_停止按钮灯.OFF();
                                Machine.do_复位按钮灯.ON();
                            }
                            break;
                            case MachineStatus.Ready://绿灯闪烁
                            {
                                Machine.do_红灯.OFF();
                                Machine.do_黄灯.OFF();
                                Machine.do_绿灯.Toggle();
                                Machine.do_蜂鸣器.OFF();

                                Machine.do_启动按钮灯.Toggle();
                                Machine.do_停止按钮灯.OFF();
                                Machine.do_复位按钮灯.OFF();
                            }
                            break;
                            case MachineStatus.Alarm:
                            case MachineStatus.Emerg://红灯闪烁，蜂鸣器闪烁
                            {
                                Machine.do_红灯.Toggle();
                                Machine.do_黄灯.OFF();
                                Machine.do_绿灯.OFF();

                                if(isShiedWarning)
                                {
                                    Machine.do_蜂鸣器.OFF();
                                }
                                else
                                {
                                    Machine.do_蜂鸣器.Toggle();
                                }

                                Machine.do_启动按钮灯.OFF();
                                Machine.do_停止按钮灯.Toggle();
                                Machine.do_复位按钮灯.OFF();
                            }
                            break;
                            case MachineStatus.Quit://退出，关闭三色灯和蜂鸣器
                            {
                                Machine.do_红灯.OFF();
                                Machine.do_黄灯.OFF();
                                Machine.do_绿灯.OFF();
                                Machine.do_蜂鸣器.OFF();

                                Machine.do_启动按钮灯.OFF();
                                Machine.do_停止按钮灯.OFF();
                                Machine.do_复位按钮灯.OFF();
                            }
                            return;
                            default:
                                break;
                        }
                    }
                    catch(Exception ex)
                    {
                        MachineStatusManager.CurrentMachineStatus = MachineStatus.Alarm;
                        AppendUiLog.Log("三色灯 线程扫描异常！", LogType.Error);
                        m_Logger1.Error(ex.StackTrace);
                        return;
                    }
                }

                Delay(500);
            }
        }
        #endregion

        #region 当点击机台复位按钮或者界面初始化按钮时，机台开始复位，复位完成机台处于ready状态
        public static void ThreadMethod_Home ()
        {

            while(MachineStatusManager.CurrentMachineStatus != MachineStatus.Quit)
            {
                if(((MachineStatusManager.CurrentMachineStatus == MachineStatus.Homing)) && (isCardInitialed == true))
                {

                    double MotionSpeedPercentageTemp = MachineDataManager.Instance.MotionSpeedPercentage;
                    MachineDataManager.Instance.MotionSpeedPercentage = 30;
                    try
                    {
                        if(是否联机上料PLC)
                        {
                            var s2 = dic_plcComm_Bool["stPLC_PC.Spare_BOOL[0]"];//判断机械手是否处于安全位  true,危险位置 false,安全位置
                            var s1 = dic_plcComm_Bool["stPLC_PC.bSafety_LDRbt"];//判断机械手是否处于安全位  true,危险位置 false,安全位置
                            if(!s1 && !s2)
                            { break; }
                        }
                        HomeBefore();

                        int ret = MotionControl.HomeAllAxis();
                        if(ret == 0) //轴回零
                        {
                            isAxisPosInit = true;
                            HomeAfer();

                            //等待PLC初始化完成
                            AppendUiLog.Log("等待PLC初始化完成......", LogType.Info);
                            if(是否联机上料PLC)
                            {
                                var flag = Machine.OmronPLC.Write("stPC_PLC.bBt_Rest", true);
                                while(flag.IsSuccess)
                                {
                                    if(dic_plcComm_Int["stPLC_PC.wEQPStatus"] == 1 || dic_plcComm_Int["stPLC_PC.wEQPStatus"] == 3)
                                    {
                                        break;
                                    }

                                    Thread.Sleep(100);
                                }
                            }
                            var ret_Write = Machine.OmronPLC.Write("stPC_PLC.bCCD_Comp[0]", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bAlarm_L", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bAlarm_H", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bBt_Start", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bBt_Stop", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bBt_Rest", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bBt_ManAuto", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bPut_Req[0]", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bPut_Req[1]", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bPut_LeaveAllow[0]", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bPut_LeaveAllow[1]", false);

                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bPick_Req[0]", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bPick_Req[1]", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bPick_LeaveAllow[0]", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bPick_LeaveAllow[1]", false);

                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bCCD_Comp[0]", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bCCD_Comp[1]", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bCCD_Comp_LD", false);
                            ret_Write = Machine.OmronPLC.Write("stPC_PLC.bCCD_Comp_Uld", false);

                            AppendUiLog.Log("PLC初始化完成", LogType.Info);

                            MachineStatusManager.CurrentMachineStatus = MachineStatus.Ready;
                            AppendUiLog.Log("设备整机复位完成！", LogType.Alert);
                            UpdateRuningData();
                        }
                        else
                        {
                            if(ret == 1)//超时
                            {
                                AppendUiLog.Log("轴回零超时！", LogType.Error);
                                MessageBox.Show("轴回零超时，不能启动");
                                MachineStatusManager.CurrentMachineStatus = MachineStatus.Initialized;
                            }
                            if(ret == 2)
                            {
                                AppendUiLog.Log("轴回零过程中，暂停！", LogType.Error);
                                MessageBox.Show("轴回零过程中，暂停");
                                MachineStatusManager.CurrentMachineStatus = MachineStatus.Initialized;
                            }
                            if(ret == 3)
                            {
                                AppendUiLog.Log("轴回零过程中，掉使能！", LogType.Error);
                                MessageBox.Show("轴回零过程中，掉使能");
                                MachineStatusManager.CurrentMachineStatus = MachineStatus.Initialized;
                            }
                            if(ret == 4)
                            {
                                AppendUiLog.Log("轴回零控制失败！", LogType.Error);
                                MessageBox.Show("轴回零控制失败");
                                MachineStatusManager.CurrentMachineStatus = MachineStatus.Initialized;
                            }

                        }
                    }
                    catch(Exception ex)
                    {
                        MachineStatusManager.CurrentMachineStatus = MachineStatus.Alarm;
                        AppendUiLog.Log($"轴回零异常！{ex.Message}", LogType.Error);
                        m_Logger1.Error(ex.StackTrace);
                    }
                    MachineDataManager.Instance.MotionSpeedPercentage = MotionSpeedPercentageTemp;
                }
                Thread.Sleep(10);
                Application.DoEvents();
            }
        }

        private static void HomeBefore ()
        {
            string msg = string.Empty;
            bool isTrue = true;
            while(isTrue)
            {
                msg = "";
                Thread.Sleep(10);
                if(Machine.di_上料平台1真空1反馈.GetStatus()
                    || Machine.di_上料平台1真空2反馈.GetStatus())
                {
                    msg += "上料平台1平台有料" + "\r\n";
                }

                if(Machine.di_上料平台2真空1反馈.GetStatus()
                   || Machine.di_上料平台2真空2反馈.GetStatus())
                {
                    msg += "上料平台2平台有料" + "\r\n";
                }

                if(Machine.di_扫码平台真空1反馈.GetStatus()
                    || Machine.di_扫码平台真空2反馈.GetStatus())
                {
                    msg += "扫码平台有料" + "\r\n";
                }

                if(Machine.di_检测平台真空1反馈.GetStatus() || Machine.di_检测平台真空2反馈.GetStatus())
                {
                    msg += "检测平台有料" + "\r\n";
                }

                if(Machine.di_移栽工位真空1反馈.GetStatus() || Machine.di_移栽工位真空2反馈.GetStatus())
                {
                    msg += "移栽工位有料" + "\r\n";
                }
                if(Machine.di_翻转平台真空1反馈.GetStatus() || Machine.di_翻转平台真空2反馈.GetStatus()
                    )
                {
                    msg += "翻转平台有料" + "\r\n";
                }
                if(Machine.di_下料翻转真空1反馈.GetStatus() || Machine.di_下料翻转真空1反馈.GetStatus())
                {
                    msg += "下料翻转工位有料" + "\r\n";
                }

                if(!string.IsNullOrEmpty(msg))
                {
                    MessageBox.Show($"检查各个气缸和检测平台是否有料，请人工确认此花篮的信息\r\n {msg}", "提示",
                                     MessageBoxButtons.OK,
                                     MessageBoxIcon.Information,
                                     MessageBoxDefaultButton.Button1,
                                     MessageBoxOptions.DefaultDesktopOnly);
                }
                else
                {
                    isTrue = false;
                }
            }

            Machine.do_上料平台1真空1吸.OFF();
            Machine.do_上料平台1真空2吸.OFF();
            Machine.do_上料平台2真空1吸.OFF();
            Machine.do_上料平台2真空2吸.OFF();

            Machine.do_扫码平台真空1吸.OFF();
            Machine.do_扫码平台真空2吸.OFF();

            Machine.do_检测平台真空1吸.OFF();
            Machine.do_检测平台真空2吸.OFF();
            Machine.do_翻转平台真空1吸.OFF();
            Machine.do_翻转平台真空2吸.OFF();

            Machine.do_下料翻转真空1吸.OFF();
            Machine.do_下料翻转真空2吸.OFF();

            Machine.cy_双动子平台1气缸1.Home();
            while(Machine.cy_双动子平台1气缸1.WaitHome(气缸等待时间))
            {
                MessageBox.Show("双动子平台1气缸1home点位异常");
            }
            Machine.cy_双动子平台1气缸2.Home();
            while(Machine.cy_双动子平台1气缸2.WaitHome(气缸等待时间))
            {
                MessageBox.Show("双动子平台1气缸2home点位异常");
            }
            Machine.cy_双动子平台2气缸1.Home();
            while(Machine.cy_双动子平台2气缸1.WaitHome(气缸等待时间))
            {
                MessageBox.Show("双动子平台2气缸1home点位异常");
            }
            Machine.cy_双动子平台2气缸2.Home();
            while(Machine.cy_双动子平台2气缸2.WaitHome(气缸等待时间))
            {
                MessageBox.Show("双动子平台2气缸2home点位异常");
            }

            Machine.cy_移栽工位气缸.Home();
            while(Machine.cy_移栽工位气缸.WaitHome(气缸等待时间))
            {
                MessageBox.Show("移栽工位气缸home点位异常");
            }
        }

        private static void HomeAfer ()
        {
            Machine.cy_下料翻转气缸.Home();
            while(Machine.cy_下料翻转气缸.WaitHome(气缸等待时间))
            {
                MessageBox.Show("下料翻转气缸home点位异常");
            }
            #endregion

            #region 光源
            foreach(var lightController in MachineDataManager.Instance.LightControllerList)
            {
                if(lightController.IsConnect == false)
                {
                    lightController.Connect();
                }
                lightController.CloseAllLight();
            }
            #endregion

            #region 工位初始化

            TrayLocation.Instance.Init();
            LoadingProduct.Instance.Init();
            LoadingMove.Instance.Init();

            LoadingTrans1.Instance.Init();
            LoadingTrans2.Instance.Init();

            PPG.Instance.Init();
            FlipStationPut.Instance.Init();
            FlipStationCatch.Instance.Init();

            Transform.Instance.Init();
            MeasureStation.Instance.Init();
            UnloadFlip.Instance.Init();
            UnloadingTrayLocation.Instance.Init();


            //Data_侧激光_CarrierA = new MeasureProduct(); //CarrierA
            //Data_侧激光_CarrierB = new MeasureProduct(); //CarrierA

            //Data_Loading_Fixture1 = new MeasureProduct();
            //Data_Loading_Fixture2 = new MeasureProduct();

            //Data_LoadingPanel1_Fixture1 = new MeasureProduct();
            //Data_LoadingPanel1_Fixture2 = new MeasureProduct();

            //Data_PPG_Fixture1 = new MeasureProduct();
            //Data_PPG_Fixture2 = new MeasureProduct();

            //Data_LoadingPanel2_Fixture1 = new MeasureProduct();
            //Data_LoadingPanel2_Fixture2 = new MeasureProduct();

            //Data_FlipPut_Fixture1 = new MeasureProduct();
            //Data_FlipPut_Fixture2 = new MeasureProduct();

            //Data_FlipCatch_Fixture1 = new MeasureProduct();
            //Data_FlipCatch_Fixture2 = new MeasureProduct();

            //Data_Transform_Fixture1 = new MeasureProduct();
            //Data_Transform_Fixture2 = new MeasureProduct();

            //Data_Measure_Fixture1 = new MeasureProduct();
            //Data_Measure_Fixture2 = new MeasureProduct();

            //Data_UnloadingRotate1 = new MeasureProduct();
            //Data_UnloadingRotate2 = new MeasureProduct();
            #endregion

            
            Count_CarrierA = 0;
            Command_CarrierA = 0;
            Count_CarrierB = 0;
            Command_CarrierB = 0;
            CurGRR循环次数 = 0;
            Cur点检次数 = 0;
            Common.pointCheckEnd = false;
            Common.pointCheck = false;
            Common.GRR换穴 = 0;
        }



        #region 机台左侧按钮扫描线程函数：停止、复位、启动
        /// <summary>
        /// 机台按钮扫描线程函数：停止、复位、启动
        /// </summary>
        /// 
        private static OperateResult ret_Write = new OperateResult();
        public static void ThreadMethod_ScanButton ()
        {
            bool? status_停止 = null;
            bool? status_手自动切换 = null;
            bool? status_复位 = null;
            bool? status_启动 = null;
            bool? status_安全门磁 = null;
            while(MachineStatusManager.CurrentMachineStatus != MachineStatus.Quit)
            {
                if(isCardInitialed == true)
                {
                    try
                    {
                        status_停止 = Machine.di_停止按钮.GetStatus();//!MachineDataManager.Instance.SYS_DI_Pause?.GetStatus();
                        status_复位 = Machine.di_复位按钮.GetStatus(); //MachineDataManager.Instance.SYS_DI_Reset?.GetStatus();
                        status_启动 = Machine.di_启动按钮.GetStatus();//MachineDataManager.Instance.SYS_DI_Start?.GetStatus();//按下启动，弹开停止
                        status_手自动切换 = Machine.di_手自动按钮.GetStatus();
                        if(Line == "ATL")
                        {
                            status_安全门磁 = Machine.di_上料Tray侧门1关闭.GetStatus() && Machine.di_上料Tray侧门2关闭.GetStatus();//MachineDataManager.Instance.SYS_DI_SafetyDoor?.GetStatus();
                        }
                        else
                        {
                            status_安全门磁 = Machine.di_上料Tray侧门1关闭.GetStatus();//MachineDataManager.Instance.SYS_DI_SafetyDoor?.GetStatus();

                        }
                        if(status_停止 == false || status_手自动切换 == false)
                        {
                            Pause();
                            //给PLC停止信号
                            if(是否联机上料PLC && Machine.opreateResult_Isconnect.IsSuccess)
                            {
                                Task.Run(async () =>
                                {
                                    ret_Write = Machine.OmronPLC.Write("stPC_PLC.bBt_Stop", true);
                                    await Task.Delay(1000);
                                    ret_Write = Machine.OmronPLC.Write("stPC_PLC.bBt_Stop", false);
                                });
                            }
                        }

                        if(status_安全门磁 == false && isShiledSafeDoor == false)
                        {
                            PauseSafetyDoor();
                            //给PLC停止信号
                            if(是否联机上料PLC && Machine.opreateResult_Isconnect.IsSuccess)
                            {
                                ret_Write = Machine.OmronPLC.Write("stPC_PLC.bSafetyDoor", true);
                            }
                        }

                        if(status_复位 == true)
                        {
                            Intial();
                            Task.Run(async () =>
                            {
                                ret_Write = Machine.OmronPLC.Write("stPC_PLC.bBt_Rest", true);
                                await Task.Delay(500);
                                ret_Write = Machine.OmronPLC.Write("stPC_PLC.bBt_Rest", false);
                            });
                        }

                        if(status_启动 == true && status_手自动切换 == true)
                        {
                            if(isAxisPosInit == true)
                            {
                                if(是否联机上料PLC && Machine.opreateResult_Isconnect.IsSuccess)
                                {
                                    PLCOperate_上料机();

                                    ret_Write = Machine.OmronPLC.Write("stPC_PLC.bAlarm_H", false);
                                    Task.Run(async () =>
                                    {
                                        ret_Write = Machine.OmronPLC.Write("stPC_PLC.bBt_Start", true);
                                        await Task.Delay(500);
                                        ret_Write = Machine.OmronPLC.Write("stPC_PLC.bBt_Start", false);
                                    });
                                }
                                Start();
                            }
                            else
                            {
                                if(AlarmPause("切换手动", "切换到手动走点位，请确保点位恢复到自动点附近，防止撞击", "点击确定，已恢复点位继续运行；点击取消，重新复位", "再试一次", "重新复位") == DialogResult.OK)
                                {
                                    isAxisPosInit = true;
                                    Start();
                                }
                            }
                        }
                        if(status_手自动切换 == true)
                        {
                            if(是否联机上料PLC && Machine.opreateResult_Isconnect.IsSuccess)
                                ret_Write = Machine.OmronPLC.Write("stPC_PLC.bBt_ManAuto", true);
                        }
                        else if(status_手自动切换 == false)
                        {
                            if(是否联机上料PLC && Machine.opreateResult_Isconnect.IsSuccess)
                                ret_Write = Machine.OmronPLC.Write("stPC_PLC.bBt_ManAuto", false);
                        }
                    }
                    catch(Exception ex)
                    {
                        if(AlarmPause("IO扫描异常", "按钮IO扫描异常", "点击确定，再试一次；点击取消，重启软件，检查板卡是否掉线", "再试一次", "重启软件，检查板卡") == DialogResult.Cancel)
                        {
                            //Stop();
                            //Common.isCardInitialed = false;
                        }
                    }
                }
                Thread.Sleep(400);
                Application.DoEvents();
            }
        }

        #endregion

        #region 停机报警
        public static DialogResult AlarmPause (string title, string excMsg, string exSolution, string okOperationTip, string cancelOperationTip)
        {
            //  MachineStatusManager.CurrentMachineStatus = MachineStatus.Alarm;
            AppendUiLog.Log(excMsg + exSolution, LogType.Error);

            DateTime startTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));


            DialogResult dr = MessageBox.Show(excMsg + Environment.NewLine
                + "【原因(解决方案)】" + exSolution + Environment.NewLine
                + "【确定】" + okOperationTip + Environment.NewLine
                + "【取消】" + cancelOperationTip, title, MessageBoxButtons.OKCancel);

            if(dr == DialogResult.OK)
            {
                excMsg += ",点击【确定】" + okOperationTip;
            }
            else
            {
                excMsg += ",点击【取消】" + cancelOperationTip;
            }


            DateTime endTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss").ToString());

            int timeCount = (endTime - startTime).Seconds;

            AlarmInfo alarmInfo = new AlarmInfo()
            {
                StartTime = startTime,
                EndTime = endTime,
                TimeCount = timeCount,
                Type = title,
                Description = excMsg
            };

            AlarmInfoServices AlarmInfoServices = new AlarmInfoServices();
            AlarmInfoServices.Add(alarmInfo);

            return dr;

        }
        public static DialogResult AlarmPause (string title, string excMsg, string exSolution, string okOperationTip)
        {
            MachineStatusManager.CurrentMachineStatus = MachineStatus.Alarm;
            AppendUiLog.Log(excMsg + exSolution, LogType.Error);

            DateTime startTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

            DialogResult dr = MessageBox.Show(excMsg + Environment.NewLine
               + "【原因(解决方案)】" + exSolution + Environment.NewLine
               + "【确定】" + okOperationTip + Environment.NewLine,
               title, MessageBoxButtons.OK);

            if(dr == DialogResult.OK)
            {
                excMsg += ",点击【确定】" + okOperationTip;
            }


            DateTime endTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss").ToString());

            int timeCount = (endTime - startTime).Seconds;

            AlarmInfo alarmInfo = new AlarmInfo()
            {
                StartTime = startTime,
                EndTime = endTime,
                TimeCount = timeCount,
                Type = title,
                Description = excMsg
            };

            AlarmInfoServices AlarmInfoServices = new AlarmInfoServices();
            if(alarmInfo.Type != "IO读写异常")
            {
                AlarmInfoServices.Add(alarmInfo);
            }

            return dr;

        }
        public static DialogResult AlarmPause (string title, string excMsg, string exSolution, string yesOperationTip, string noOperationTip, string cancelOperationTip)
        {
            MachineStatusManager.CurrentMachineStatus = MachineStatus.Alarm;
            AppendUiLog.Log(excMsg + exSolution, LogType.Error);

            DateTime startTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));


            DialogResult dr = MessageBox.Show(excMsg + Environment.NewLine
                + "【原因(解决方案)】" + exSolution + Environment.NewLine
                + "【是】" + yesOperationTip + Environment.NewLine
                + "【否】" + noOperationTip + Environment.NewLine
                + "【取消】" + cancelOperationTip,
                title, MessageBoxButtons.YesNoCancel);

            if(dr == DialogResult.Yes)
            {
                excMsg += ",点击【是】" + yesOperationTip;
            }
            else if(dr == DialogResult.No)
            {
                excMsg += ",点击【否】" + noOperationTip;
            }
            else
            {
                excMsg += ",点击【取消】" + cancelOperationTip;
            }

            DateTime endTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss").ToString());

            int timeCount = (endTime - startTime).Seconds;

            AlarmInfo alarmInfo = new AlarmInfo()
            {
                StartTime = startTime,
                EndTime = endTime,
                TimeCount = timeCount,
                Type = title,
                Description = excMsg
            };

            AlarmInfoServices AlarmInfoServices = new AlarmInfoServices();
            AlarmInfoServices.Add(alarmInfo);

            return dr;

        }
        #endregion

        #region 扫描轴运动状态的函数
        /// <summary>
        /// 扫描轴运动状态的函数
        /// </summary>
        public static void ThreadMethod_AxisStatus ()
        {
            bool isRun = true;
            while(MachineStatusManager.CurrentMachineStatus != MachineStatus.Quit && isRun)
            {
                Thread.Sleep(100);
                Application.DoEvents();
                if(isCardInitialed == false)
                {
                    continue;
                }
                //检测轴报警
                string txt_MotorAlarmNo = string.Empty;

                foreach(var axis in MachineDataManager.Instance.AxisList)
                {
                    try
                    {
                        if(axis.GetAlarm() == true)
                        {

                            DialogResult dr = AlarmPause("轴报警", "轴[" + axis.Name + "]电机报警",
                                      "手动清除报警后重新打开软件，或点击确定尝试自动清除报警！", "尝试自动清除报警", "手动清除，重启软件", "不检查轴报警");
                            if(dr == DialogResult.Yes)
                            {
                                try
                                {
                                    axis.ClearAlarm();
                                }
                                catch { }
                                Thread.Sleep(500);
                            }
                            else if(dr == DialogResult.No)
                            {
                                try
                                {
                                    MotionControl.AllAxisServoOff();
                                }
                                catch { }

                                //记录软件关闭时间
                                DateTime startTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

                                Machine.AdlinkCard?.Finalize();

                                DateTime endTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

                                TimeSpan ts = endTime - startTime;
                                int timeCount = (int)ts.TotalSeconds;
                                AlarmInfo alarmInfo = new AlarmInfo()
                                {
                                    StartTime = startTime,
                                    EndTime = endTime,
                                    TimeCount = timeCount,
                                    Type = "轴报警",
                                    Description = axis.Name + "报警," + ""
                                };

                                AlarmInfoServices AlarmInfoServices = new AlarmInfoServices();
                                AlarmInfoServices.Add(alarmInfo);

                                StopMachine();
                                Application.Exit();
                                Environment.Exit(-1);//直接退出不提示
                            }
                            else
                            {
                                isRun = false;
                                break;
                            }
                        }
                    }
                    catch(Exception) { }
                }
            }
        }
        #endregion

        #region 机台控制方法：StopMachine，PauseMachine，AwakeMachine
        public static void StopMachine ()
        {
            #region 关闭光源
            #endregion

            PauseMachine();

            MotionControl.AllAxisServoOff();
            foreach(var card in MachineDataManager.Instance.CardList)
            {
                //关闭卡片
                if(card?.Initialized == true)
                {
                    card.Finalize();
                }
            }
        }
        private static void PauseMachine ()
        {
            CT.Stop();
            foreach(var axis in MachineDataManager.Instance.AxisList)
            {
                axis.IsStop = true;
            }
        }
        #endregion

        #region 监控EMG线程
        public static void ThreadMethod_EMGStatus ()
        {
            while(MachineStatusManager.CurrentMachineStatus != MachineStatus.Quit)
            {
                if(isCardInitialed == true)
                {
                    //if (Machine.di_急停.GetStatus() == false)  //急停拍下
                    {
                        //if (MessageBox.Show("Motor Alarm" + Environment.NewLine + "Clear the EMG?", "Clear the EMG?", MessageBoxButtons.OKCancel) == DialogResult.OK)
                        {
                            //if (!Machine.di_ControlOn反馈.GetStatus())
                            //{
                            //    Common.AppendUiLog.Log("Please Control On First!", LogType.Error);
                            //    MessageBox.Show("Please Control On First!", " Control On", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                            //    Thread.Sleep(1000);
                            //    continue;
                            //}

                            //给所有轴上伺服
                            //Machine.AdlinkCard.AllAxisServoON();
                        }
                    }
                }

                Thread.Sleep(10);
                Application.DoEvents();
            }
        }
        #endregion

        #region 监控门信号线程
        private static bool isSafetyScreenTrig = false;
        public static void ThreadMethod_DoorStatus ()
        {
            while(MachineStatusManager.CurrentMachineStatus != MachineStatus.Quit)
            {
                if(isCardInitialed == true)
                {
                    //安全门
                    if(isShiledSafeDoor == false)//安全门未屏蔽
                    {
                        bool DoorSgn1 = false;
                        if(Line == "ATL")
                        {
                            if(!是否联机上料PLC)
                            {
                                DoorSgn1 = Machine.di_上料操作侧门1关闭.GetStatus() || Machine.di_上料操作侧门2关闭.GetStatus() || Machine.di_上料Tray侧门1关闭.GetStatus() || Machine.di_上料Tray侧门2关闭.GetStatus() || Machine.di_下料操作侧门1关闭.GetStatus() || Machine.di_下料操作侧门2关闭.GetStatus() || Machine.di_下料操作侧门3关闭.GetStatus();

                            }
                            else
                            {

                                DoorSgn1 = dic_plcComm_Bool["stPLC_PC.bSafetyDoor"] || Machine.di_上料操作侧门1关闭.GetStatus() || Machine.di_上料操作侧门2关闭.GetStatus() || Machine.di_上料Tray侧门1关闭.GetStatus() || Machine.di_上料Tray侧门2关闭.GetStatus() || Machine.di_下料操作侧门1关闭.GetStatus() || Machine.di_下料操作侧门2关闭.GetStatus() || Machine.di_下料操作侧门3关闭.GetStatus();
                            }

                        }
                        else
                        {
                            if(!是否联机上料PLC)
                            {
                                //zan bu kai qi an quan men 
                                DoorSgn1 = Machine.di_上料操作侧门1关闭.GetStatus() || Machine.di_上料操作侧门2关闭.GetStatus() || Machine.di_上料Tray侧门1关闭.GetStatus() || Machine.di_下料操作侧门1关闭.GetStatus() || Machine.di_下料操作侧门2关闭.GetStatus();

                            }
                            else
                            {
                                //zan bu kai qi an quan men 
                                DoorSgn1 = dic_plcComm_Bool["stPLC_PC.bSafetyDoor"] || Machine.di_上料操作侧门1关闭.GetStatus() || Machine.di_上料操作侧门2关闭.GetStatus() || Machine.di_上料Tray侧门1关闭.GetStatus() || Machine.di_下料操作侧门1关闭.GetStatus() || Machine.di_下料操作侧门2关闭.GetStatus();
                            }
                        }

                        if(true == DoorSgn1)
                        {
                            Machine.OmronPLC.Write("stPC_PLC.bSafetyDoor", true);

                            MachineStatusManager.CurrentMachineStatus = MachineStatus.Alarm;//报警
                            AppendUiLog.Log("Check , doors are opened!", LogType.Error);
                            MessageBox.Show("请检查 , 安全门被打开!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                        else
                        {
                            Machine.OmronPLC.Write("stPC_PLC.bSafetyDoor", false);
                        }

                        ////监控安全门
                        //if (MachineDataManager.Instance.SYS_DI_SafetyDoor?.GetStatus() == false)//
                        //{
                        //    Frm_Main.Instance.label_Guangshan.BackColor = Color.Red;
                        //}
                        //else
                        //{
                        //    Frm_Main.Instance.label_Guangshan.BackColor = Color.Green;
                        //}
                    }


                    if(isShiledSafeScreen == false)
                    {
                        bool? SafeScreen = MachineDataManager.Instance.SYS_DI_SafetyScreen?.GetStatus();

                        if((true == SafeScreen))
                        {
                            if(MachineStatusManager.CurrentMachineStatus == MachineStatus.Running)
                            {
                                Pause();
                                if(isSafetyScreenTrig == false)
                                {
                                    AppendUiLog.Log("Safety Screen Trig!", LogType.Error);
                                    isSafetyScreenTrig = true;
                                }
                            }
                        }
                        else
                        {
                            isSafetyScreenTrig = false;

                            if(MachineStatusManager.CurrentMachineStatus == MachineStatus.Pause)
                                Start();
                        }
                    }
                }

                //设备状态显示
                Frm_Main.Instance.lbl_Status.Text = MachineStatusManager.CurrentMachineStatus.ToString();
                if(MachineStatusManager.CurrentMachineStatus == MachineStatus.Unknown
                    || MachineStatusManager.CurrentMachineStatus == MachineStatus.Alarm)
                {
                    Frm_Main.Instance.lbl_Status.BackColor = Color.Red;
                }
                else if(MachineStatusManager.CurrentMachineStatus == MachineStatus.Running)
                {
                    Frm_Main.Instance.lbl_Status.BackColor = Color.Green;
                }
                else
                {
                    Frm_Main.Instance.lbl_Status.BackColor = Color.Yellow;
                }
                Thread.Sleep(200);
                Application.DoEvents();
            }
        }
        #endregion

        #region Quebec
        public enum AxisName
        {
            X1, X2, X3, Y1, Y2, Y3, Y4, Y5, Y6, Y7, R1, R2, Z1, X7, X8
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 截屏
        /// </summary>
        public static void CaptureScreen ()
        {
            //屏幕宽
            int userWidth = Screen.PrimaryScreen.Bounds.Width;
            //屏幕高
            int userHeight = Screen.PrimaryScreen.Bounds.Height;
            //按照屏幕宽高创建位图
            Image img = new Bitmap(userWidth, userHeight);
            //从一个继承自Image类的对象中创建Graphics对象
            Graphics gc = Graphics.FromImage(img);
            //抓屏并拷贝到myimage里
            gc.CopyFromScreen(new System.Drawing.Point(0, 0), new System.Drawing.Point(0, 0), new System.Drawing.Size(userWidth, userHeight));
            //this.BackgroundImage = img;
            //保存位图
            string fileNameExt = "Capture_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".jpg";//文件名
            string path = Application.StartupPath + @"\Log\CaptureScreen\" + fileNameExt;
            img.Save(path);
        }

        #region 点云转real图片
        public static bool PointsToRealImage (out HObject Image, HTuple width, HTuple height, List<double> pointList)
        {
            Image = new HObject();
            if(width <= 0 || height <= 0)
            {
                return false;
            }
            if(pointList == null || pointList.Count <= 0)
            {
                return false;
            }
            HTuple rowSequence = new HTuple();
            HTuple colSequence = new HTuple();
            try
            {
                double[] points = pointList.ToArray();

                HOperatorSet.GenImageConst(out Image, "real", width, height); //行列互换一下
                HOperatorSet.GetRegionPoints(Image, out rowSequence, out colSequence);
                HOperatorSet.SetGrayval(Image, rowSequence, colSequence, points);
            }
            catch(Exception)
            {
                throw new Exception("点云转换失败");
            }

            return true;
        }

        #endregion

        #region 保存图片
        public static bool SaveImage (HObject[] images)
        {
            bool ret = true;
            try
            {
                string path = picSavePath + "\\" + DateTime.Now.Year + "-" + DateTime.Now.Month + "-" + DateTime.Now.Day;
                if(!FileUtils.IsExistDirectory(path))
                {
                    FileUtils.CreateDirectory(path);
                }
                foreach(HObject image in images)
                {
                    HOperatorSet.WriteImage(image, "bmp", 0, path + "\\" + DateTime.Now.Hour + "_" + DateTime.Now.Minute + "_" + DateTime.Now.Second + "_" + DateTime.Now.Millisecond);
                }
            }
            catch(Exception exc)
            {
                ret = false;
            }
            return ret;
        }
        public static bool SaveImage (HObject image)
        {
            bool ret = true;
            try
            {
                string path = picSavePath + "\\" + DateTime.Now.Year + "-" + DateTime.Now.Month + "-" + DateTime.Now.Day;
                if(!FileUtils.IsExistDirectory(path))
                {
                    FileUtils.CreateDirectory(path);
                }
                HOperatorSet.WriteImage(image, "bmp", 0, path + "\\" + DateTime.Now.Hour + "_" + DateTime.Now.Minute + "_" + DateTime.Now.Second + "_" + DateTime.Now.Millisecond);
            }
            catch(Exception exc)
            {
                ret = false;
            }
            return ret;
        }
        public static bool SaveImage (Bitmap image)
        {
            bool ret = true;
            try
            {
                string path = picSavePath + "\\" + DateTime.Now.Year + "-" + DateTime.Now.Month + "-" + DateTime.Now.Day;
                if(!FileUtils.IsExistDirectory(path))
                {
                    FileUtils.CreateDirectory(path);
                }
                image.Save(path + "\\" + DateTime.Now.Hour + "_" + DateTime.Now.Minute + "_" + DateTime.Now.Second + "_" + DateTime.Now.Millisecond + ".bmp");
            }
            catch(Exception exc)
            {
                ret = false;
            }
            return ret;
        }
        public static bool SaveImage (HObject image, string folderName)
        {
            bool ret = true;
            try
            {
                string path = picSavePath + "\\" + startDate + "\\" + startTime.Replace(":", "_") + "\\" + folderName;
                if(!FileUtils.IsExistDirectory(path))
                {
                    FileUtils.CreateDirectory(path);
                }
                HOperatorSet.WriteImage(image, "jpge", 0, path + "\\" + DateTime.Now.Hour + "_" + DateTime.Now.Minute + "_" + DateTime.Now.Second + "_" + DateTime.Now.Millisecond);
            }
            catch(Exception exc)
            {
                ret = false;
            }
            return ret;
        }
        public static bool SaveImage (Bitmap image, string folderName)
        {
            bool ret = true;
            try
            {
                string path = picSavePath + "\\" + startDate + "\\" /*+ Common.startTime.Replace(":", "_") + "\\"*/ + folderName;
                if(!FileUtils.IsExistDirectory(path))
                {
                    FileUtils.CreateDirectory(path);
                }
                image.Save(path + "\\" + DateTime.Now.Hour + "_" + DateTime.Now.Minute + "_" + DateTime.Now.Second + "_" + DateTime.Now.Millisecond + ".bmp");
            }
            catch(Exception exc)
            {
                ret = false;
            }
            return ret;
        }

        private static readonly object obj1 = new object();
        public static bool SaveImageWithBarCode (HObject image, string dirPath, string ImagName)
        {
            lock(obj1)
            {
                bool ret = true;
                try
                {
                    if(!FileUtils.IsExistDirectory(dirPath))
                    {
                        FileUtils.CreateDirectory(dirPath);
                    }
                    HOperatorSet.WriteImage(image, "bmp", 0, dirPath + "\\" + ImagName);//+ DateTime.Now.ToString("_HH_mm_ss")
                }
                catch(Exception exc)
                {
                    ret = false;
                }
                return ret;
            }

        }
        public static bool SaveRobotImage (HObject image)
        {
            bool ret = true;
            try
            {
                string path = picSavePath + "\\" + "机械臂引导" + "\\" + DateTime.Now.Year + "-" + DateTime.Now.Month + "-" + DateTime.Now.Day;
                if(!FileUtils.IsExistDirectory(path))
                {
                    FileUtils.CreateDirectory(path);
                }
                HOperatorSet.WriteImage(image, "bmp", 0, path + "\\" + DateTime.Now.Hour + "_" + DateTime.Now.Minute + "_" + DateTime.Now.Second + "_" + DateTime.Now.Millisecond);
            }
            catch(Exception exc)
            {
                ret = false;
            }
            return ret;
        }
        public static async Task SaveRobotErrorImage (HObject image, string folderName)
        {
            await Task.Run(() =>
            {
                try
                {
                    string path = picSavePath + "\\" + "机械臂引导" + "\\" + folderName + "\\" + DateTime.Now.Year + "-" + DateTime.Now.Month + "-" + DateTime.Now.Day;
                    if(!FileUtils.IsExistDirectory(path))
                    {
                        FileUtils.CreateDirectory(path);
                    }

                    HOperatorSet.WriteImage(image, "bmp", 0, path + "\\" + DateTime.Now.Hour + "_" + DateTime.Now.Minute + "_" + DateTime.Now.Second + "_" + DateTime.Now.Millisecond);

                }
                catch(Exception exc)
                {
                    m_Logger1.Error("SaveRobotErrorImage Exception! ::" + exc.StackTrace);
                }
            });
        }
        #endregion

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="strLog"></param>
        /// <param name="fileName"></param>
        public static void WriteLogToTxt (string strLog, string fileName, string station)
        {
            try
            {
                String System_Now_Time = null;
                String File_Create_Time = null;

                System_Now_Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                File_Create_Time = DateTime.Now.ToString("yyyyMMdd");
                string logDocument = $"{station}_{File_Create_Time}.csv";

                string str = Process.GetCurrentProcess().MainModule.FileName;
                string logFilePath = str.Substring(0, str.LastIndexOf("\\")) + "\\ALog\\" + fileName;

                if(!Directory.Exists(logFilePath))
                {
                    Directory.CreateDirectory(logFilePath);
                }
                logFilePath = logFilePath + "//" + logDocument;

                if(!File.Exists(logFilePath))
                {
                    File.AppendAllText(logFilePath, $"Time,Station,StationInfo,CT,{Environment.NewLine}", Encoding.GetEncoding(0));
                }

                File.AppendAllText(logFilePath, System_Now_Time + "," + strLog + Environment.NewLine, Encoding.GetEncoding(0));

            }
            catch(Exception ex)
            {
                AppendUiLog.Log(ex.StackTrace, LogType.Error);
                //MessageBox.Show("写日志文件失败！\r\n", "写日志文件失败,点击确定重试一次，点击取消放弃保存！", MessageBoxButtons.OKCancel);
            }

        }

        public static string Header = "Time,Position,Line,MeasureId,OK_NG,NG_FAI,Barcode,PPG";
        public static int j = 0;
        public static void WritePPG (MeasureProduct measureProduct, double ppgValue, string path = "D:\\Data\\ppg.csv")
        {
            string str = string.Empty;
            string values = string.Empty;
            str += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ",";
            str += measureProduct.Position + ",";
            str += Line + ",";
            j++;
            str += j.ToString() + ",";
            str += ",";
            str += ",";
            if(measureProduct.SN == "")
            {
                measureProduct.SN = "_";
            }
            str += measureProduct.SN;
            values = str + "," + ppgValue;

            FileInfo file = new FileInfo(path);
            if(!file.Directory.Exists)
                file.Directory.Create();
            if(!file.Exists)
            {
                FileUtils.AppendText(path, Header + "\r\n");
            }

            FileUtils.AppendText(path, values + "\r\n");
        }
        #endregion

        private static readonly object _lock1 = new object();
        public static void WriteLogToTxt (string strLog, string FileName)
        {
            lock(_lock1)
            {
                try
                {
                    String System_Now_Time = null;
                    String File_Create_Time = null;

                    System_Now_Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"); //"HH:mm:ss
                    File_Create_Time = DateTime.Now.ToString("yyyyMMdd");
                    string logDocument = File_Create_Time + ".txt";

                    string str = Process.GetCurrentProcess().MainModule.FileName;
                    string logFilePath = str.Substring(0, str.LastIndexOf("\\")) + "\\" + "CT_1" + "\\" + FileName;//VisionSendMessage";
                    if(!Directory.Exists(logFilePath))
                    {
                        Directory.CreateDirectory(logFilePath);
                    }
                    logFilePath = logFilePath + "//" + logDocument;
                    FileStream fs = new FileStream(logFilePath, FileMode.Append);
                    StreamWriter sw = new StreamWriter(fs, Encoding.Default);
                    sw.WriteLine(System_Now_Time + ":   " + strLog);
                    sw.Flush();
                    sw.Close();
                    fs.Close();
                }
                catch(Exception ex)
                {
                    AppendUiLog.Log(ex.StackTrace, LogType.Error);
                    MessageBox.Show("写日志文件失败！\r\n", "写日志文件失败,点击确定重试一次，点击取消放弃保存！", MessageBoxButtons.OKCancel);
                }
            }



        }

        private static readonly object _lock = new object();
        public static void WriteLogToTxtLaser (string strLog, string FileName)
        {
            lock(_lock)
            {
                try
                {
                    String System_Now_Time = null;
                    String File_Create_Time = null;

                    System_Now_Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"); //"HH:mm:ss
                    File_Create_Time = DateTime.Now.ToString("yyyyMMdd");
                    string logDocument = File_Create_Time + ".txt";

                    string str = Process.GetCurrentProcess().MainModule.FileName;
                    string logFilePath = str.Substring(0, str.LastIndexOf("\\")) + "\\" + "CT_1" + "\\" + FileName;//VisionSendMessage";
                    if(!Directory.Exists(logFilePath))
                    {
                        Directory.CreateDirectory(logFilePath);
                    }
                    logFilePath = logFilePath + "//" + logDocument;
                    FileStream fs = new FileStream(logFilePath, FileMode.Append);
                    StreamWriter sw = new StreamWriter(fs, Encoding.Default);
                    sw.WriteLine(System_Now_Time + ":   " + strLog);
                    sw.Flush();
                    sw.Close();
                    fs.Close();
                }
                catch(Exception ex)
                {
                    AppendUiLog.Log(ex.StackTrace, LogType.Error);
                    MessageBox.Show("写日志文件失败！\r\n", "写日志文件失败,点击确定重试一次，点击取消放弃保存！", MessageBoxButtons.OKCancel);
                }

            }
        }


        #region MindVision相机相关函数
        public static bool MindVision ()
        {
            AppendUiLog.Log("MindVision LoadingProduct1……", LogType.Info);
            if(MVCameraList.IsConnected == false)//仅复位使用，设置中不可将值赋值为True，防止有相机未连接
            {
                CloseAllCam();
                MVCameraList.Clear();
                List<bool> camStatus = new List<bool>();
                AppendUiLog.Log("初始化相机……", LogType.Info);
                foreach(CameraModel cam in CameraParams)
                {
                    try
                    {

                        MVCameraList.NewObject(cam.CameraName);
                        bool ret1 = MVCameraList.Connect(cam.CameraName, cam.CameraSN, 1);
                        bool ret2 = MVCameraList.LoadConfig(cam.CameraName, cam.CameraPath);
                        if(ret1 && ret2)
                        {
                            camStatus.Add(true);
                        }
                        else
                        {
                            if(ret1 == false)
                                AppendUiLog.Log("CameraName：" + cam.CameraName + ",相机连接失败", LogType.Error);
                            if(ret2 == false)
                                AppendUiLog.Log("CameraName：" + cam.CameraName + ",参数加载失败", LogType.Error);
                            camStatus.Add(false);
                        }
                    }
                    catch(Exception mv)
                    {
                        AppendUiLog.Log("相机加载异常：" + mv.ToString(), LogType.Error);
                        camStatus.Add(false);
                    }
                }
                if(camStatus.Contains(false))
                {
                    AppendUiLog.Log("相机未全部加载成功,建议停机检查相机设置及端口是否被打开……", LogType.Error);
                    MVCameraList.IsConnected = false;
                    return false;
                }
                else
                {
                    AppendUiLog.Log("相机全部加载成功……IsConnected：TRUE", LogType.Info);
                    MVCameraList.IsConnected = true;//防止重复加载相机，消耗内存
                    return true;
                }
            }
            else
            {
                AppendUiLog.Log("相机已连接，不需要再次连接", LogType.Info);
                return true;
            }
        }


        public static readonly object lockCam = new object();
        public static bool ReconnectCam (ref MVController camTemp, string camName)
        {
            lock(lockCam)
            {
                bool ret = false;
                try
                {
                    CameraModel camParam = CameraParams.SingleOrDefault(n => n.CameraName == camName);
                    if(camParam == null && camTemp == null)
                    {
                        return false;
                    }
                    if(camTemp.IsConnected)
                    {
                        Thread.Sleep(500);
                        AppendUiLog.Log(camName + "相机在线", LogType.Info);
                    }

                    ret = camTemp.Connect(camParam.CameraSN, 1);
                    ret &= camTemp.LoadParameterFromFile(camParam.CameraPath);
                }
                catch(Exception e1)
                {
                    AppendUiLog.Log(camName + "相机异常" + e1.ToString(), LogType.Error);
                    return false;
                }
                return ret;
            }
        }

        public static bool CloseAllCam ()
        {
            if(MVCameraList.getCount() > 0)
            {
                foreach(CameraModel cam in CameraParams)
                {
                    try
                    {
                        if(MVCameraList.getObject(cam.CameraName) != null)//防止手动添加导致==null，抛异常
                        {
                            MVCameraList.getObject(cam.CameraName).Close();
                        }
                    }
                    catch(Exception e)
                    {
                        AppendUiLog.Log("相机关闭异常：" + e.ToString(), LogType.Error);
                    }
                }
            }
            return true;
        }
        #endregion

        #region ACMT SSZN激光初始化函数
        public static List<bool> SSZNLaserInit ()
        {
            List<bool> ret = new List<bool>();
            bool retLaser = false;

            try
            {
                //上激光1
                UpLaser1.currentDeviceId = 0;
                retLaser = UpLaser1.Connect(UpLaser_SN);
                ret.Add(retLaser);
                if(!retLaser)
                {
                    Frm_InitItemStatu.Instance.UpdateStep(50, "初始化上激光1失败!", false);
                    AppendUiLog.Log("初始化上激光1失败", LogType.Error);
                }
                else
                {
                    Frm_InitItemStatu.Instance.UpdateStep(50, "初始化上激光1成功!", true);
                    AppendUiLog.Log("初始化上激光1成功", LogType.Info);
                }

                //下激光1
                DownLaser1.currentDeviceId = 1;
                retLaser = DownLaser1.Connect(DownLaser_SN);
                ret.Add(retLaser);
                if(!retLaser)
                {
                    Frm_InitItemStatu.Instance.UpdateStep(50, "初始化下激光1失败!", false);
                    AppendUiLog.Log("初始化下激光1失败", LogType.Error);
                }
                else
                {
                    Frm_InitItemStatu.Instance.UpdateStep(50, "初始化下激光1成功!", true);
                    AppendUiLog.Log("初始化下激光1成功", LogType.Info);
                }
            }
            catch(Exception ex)
            {
                AppendUiLog.Log("初始化SSZN激光异常 " + ex.ToString(), LogType.Error);
            }

            return ret;
        }
        #endregion

        public static bool SaveImageWithBarCode (HObject image, string folderName, string BarCode, string ImagName)
        {
            bool ret = true;
            try
            {
                string path = picSavePath + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + "\\" + CurProType + "\\" + BarCode;// + "\\" + folderName;
                if(!FileUtils.IsExistDirectory(path))
                {
                    FileUtils.CreateDirectory(path);
                }
                HOperatorSet.WriteImage(image, "bmp", 0, path + "\\" + ImagName);//+ DateTime.Now.ToString("_HH_mm_ss")
            }
            catch(Exception exc)
            {
                ret = false;
            }
            return ret;
        }

        public static bool ChangeProjectExvent ()
        {

            var changeRet = true;
            Dlg_Notice dlg_Notice = new Dlg_Notice();
            dlg_Notice.TopMost = true;
            dlg_Notice.Show();
            Application.DoEvents();
            //切视觉算法
            //dlg_Notice.UpdateStep(5, "正在切换算法...", true);
            bool ret = false;
            ret = true;

            //ret = LoadSlp(CurProType);
            //if (ret)
            //    dlg_Notice.UpdateStep(30, "切换算法完成", ret);
            //else
            //    dlg_Notice.UpdateStep(30, "切换算法失败,文件不存在", ret);

            //dlg_Notice.UpdateStep(35, "正在切换激光参数...", true);
            //切换激光参数
            //ret = ChangeLaserParam(CurProType);
            changeRet &= ret;
            //if (ret)
            //    dlg_Notice.UpdateStep(75, "切换激光参数完成", ret);
            //else
            //    dlg_Notice.UpdateStep(75, "切换激光参数失败", ret);

            dlg_Notice.UpdateStep(80, "正在切换光源项目源...", true);
            //切换光源项目源
            ret = Machine.ImageLightInit(CurProType);
            changeRet &= ret;
            if(ret)
                dlg_Notice.UpdateStep(100, "切换光源项目源完成", ret);
            else
                dlg_Notice.UpdateStep(100, "切换光源项目源失败", ret);

            if(changeRet)
                dlg_Notice.Close();
            else
            {
                dlg_Notice.FormBorderStyle = FormBorderStyle.FixedSingle;

                dlg_Notice.lbl_NoticeTxt.Text = "参数修改失败";
                dlg_Notice.lbl_HandleTxt.Text = "请查看失败项";
            }


            AppendUiLog.Log($"切换产品类型={CurProType},算法切换Slp, 光源切换结果={ret}", LogType.Alert);
            return changeRet;
        }


        public static bool ChangeLaserParam (string ProType)
        {
            var ret = true;
            ret &= SSLaserChangeProgram(ProType);
            ret &= KeyenceLaserChangeProgram(ProType);
            if(ret)
                AppendUiLog.Log($"激光切换程序{ProType}成功", LogType.Alert);
            else
                AppendUiLog.Log($"激光切换程序{ProType}失败", LogType.Error);

            return ret;
        }

        public static bool SSLaserChangeProgram (string ProType)
        {
            byte ProgramNo = 0;
            if(CurProType == "Block")
            {
                ProgramNo = 1;
            }
            else if(CurProType == "Product")
            {
                ProgramNo = 2;
            }
            var ret = true;
            ////ret &= DownLaser21.ChangeActiveProgram(ProgramNo);
            //ret &= DownLaser22.ChangeActiveProgram(ProgramNo);
            //ret &= UpLaser1.ChangeActiveProgram(ProgramNo);
            //if (Common.Line.Equals(Common.LineName.右.ToString()))
            //{
            //    ret &= DownLaser1.ChangeActiveProgram(ProgramNo);
            //    DownLaser1.Start();
            //    DownLaser1.Stop();
            //}
            ////DownLaser21.Start();
            ////DownLaser21.Stop();
            ////DownLaser22.Start();
            ////DownLaser22.Stop();
            ////UpLaser1.Start();
            ////UpLaser1.Stop();
            return ret;
        }

        public static bool KeyenceLaserChangeProgram (string ProType)
        {
            byte ProgramNo = 0;
            if(CurProType == "Block")
            {
                ProgramNo = 0;
            }
            else if(CurProType == "Product")
            {
                ProgramNo = 1;
            }
            var ret = true;
            //ret &= SideLaser1.ChangeActiveProgram(ProgramNo);
            //ret &= SideLaser2.ChangeActiveProgram(ProgramNo);
            //ret &= SideLaser3.ChangeActiveProgram(ProgramNo);
            //SideLaser1.Start();
            //SideLaser1.Stop();
            //SideLaser2.Start();
            //SideLaser2.Stop();
            //SideLaser3.Start();
            //SideLaser3.Stop();
            return ret;
        }
        public static bool LoadSlp (string ProType)
        {
            var slpPath = "";
            if(CurProType == "Block")
            {
                if(Common.Line == "MUR")
                {
                    slpPath = "D:\\NDK-Software\\SLP\\ACMT.slp";
                }
                else
                {
                    slpPath = "D:\\NDK-Software\\SLP\\ACMT-Block.slp";
                }
            }
            else if(CurProType == "Product")
            {
                if(Common.Line == "MUR")
                {
                    slpPath = "D:\\NDK-Software\\SLP\\ACMT.slp";
                }
                else
                {
                    slpPath = "D:\\NDK-Software\\SLP\\ACMT-Block.slp";
                }
            }
            if(File.Exists(slpPath))
                Vision.LoadSlp(slpPath);
            else
                return false;

            return true;
        }


        public static void LoadProTypeParam ()
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            dic = INIUtils.GetAllKeyValues(Section_ProductTypeConfig, ProTypeIniPath);
            if(ProductTypeMeasureItemEnableList.Count > 0)
                CurProType = GetIniValue(dic, "CurProductType", $"{ProductTypeMeasureItemEnableList[0].ProductType}", ProTypeIniPath, Section_ProductTypeConfig);
            else
                CurProType = GetIniValue(dic, "CurProductType", $"{ProductType}", ProTypeIniPath, Section_ProductTypeConfig);

            dic = INIUtils.GetAllKeyValues(Section_MeasureItems, ProTypeIniPath);
            var DefaultMeasureItemsStr = GetIniValue(dic, "DefaultMeasureItems", string.Join(",", DefaultMeasureItems), ProTypeIniPath, Section_MeasureItems);
            if(!string.IsNullOrEmpty(DefaultMeasureItemsStr))
                DefaultMeasureItems = DefaultMeasureItemsStr.Split(',').ToList();
        }
        public static string GetIniValue (Dictionary<string, string> dic, string Key, string defaultValue, string path, string Section = "AFMT")
        {
            string Value = "";
            dic.TryGetValue(Key, out Value);
            if(Value == null)
            {
                INIUtils.Write(Section, Key, defaultValue, path);
                Value = defaultValue;
            }
            return Value;
        }

        public static void WriteCurProTypeIni (string value)
        {
            INIUtils.Write(Section_ProductTypeConfig, "CurProductType", value, ProTypeIniPath);
        }

        public static void LoadProTypeMeasureItemEnableConfig ()
        {
            try
            {
                ProductTypeMeasureItemEnableList.Clear();
                if(!File.Exists(ProTypeCsvPath))
                {
                    ProductTypeMeasureItemEnableList = new List<ProductTypeMeasureItemEnable>();
                    //ProductTypeMeasureItemEnableList.Add(NewDefaultProTypeMeasureItemEnable($"{Common.ProjectName}", DefaultMeasureItems));//默认以ProjectName作为项目
                    ProductTypeMeasureItemEnableList.Add(NewDefaultProTypeMeasureItemEnable($"Block", DefaultMeasureItems));//以实际项目自由添加测量种类默认
                    ProductTypeMeasureItemEnableList.Add(NewDefaultProTypeMeasureItemEnable($"Product", DefaultMeasureItems));

                    //todo sAVE
                    bool isHeader = false;
                    string ProTypeHeader = "";
                    string Values = "";
                    foreach(var productTypeMeasureItemEnable in ProductTypeMeasureItemEnableList)
                    {
                        string value = "";
                        if(!isHeader)
                            ProTypeHeader += $"产品类型,";
                        value += $"{productTypeMeasureItemEnable.ProductType},";
                        foreach(var measureItemEnable in productTypeMeasureItemEnable.MeasureItemEnableDic)
                        {
                            if(!isHeader)
                                ProTypeHeader += $"{measureItemEnable.Key},";
                            value += $"{measureItemEnable.Value},";
                        }
                        if(!isHeader)
                            ProTypeHeader += Environment.NewLine;
                        isHeader = true;
                        Values += value + Environment.NewLine;
                    }
                    FileUtils.AppendText(ProTypeCsvPath, ProTypeHeader);
                    FileUtils.AppendText(ProTypeCsvPath, Values);
                }
                else
                {
                    var dt = FileUtils.OpenCSV(ProTypeCsvPath);
                    List<string> MeasureItems = new List<string>();
                    foreach(DataColumn col in dt.Columns)
                    {
                        if(col.ColumnName.Equals("产品类型"))
                            continue;
                        MeasureItems.Add(col.ColumnName);
                    }
                    for(int i = 0; i < dt.Rows.Count; i++)
                    {
                        var name = "";
                        var NewProTypeMeasureItemsEnable = NewDefaultProTypeMeasureItemEnable(name, MeasureItems);
                        for(int j = 0; j < dt.Columns.Count; j++)
                        {
                            if(j == 0)
                            {
                                name = dt.Rows[i][j].ToString();
                                NewProTypeMeasureItemsEnable.ProductType = name;
                            }
                            else
                            {
                                DataColumn col = dt.Columns[j];
                                var key = col.ColumnName;
                                var value = false;
                                if(string.IsNullOrEmpty(dt.Rows[i][j].ToString()))
                                {
                                    value = false;
                                }
                                else
                                    value = bool.Parse(dt.Rows[i][j].ToString());

                                if(NewProTypeMeasureItemsEnable.MeasureItemEnableDic.ContainsKey(key))
                                    NewProTypeMeasureItemsEnable.MeasureItemEnableDic[key] = value;
                            }
                        }
                        var findItem = ProductTypeMeasureItemEnableList.Find(x => x.ProductType == name);
                        if(findItem == null)
                            ProductTypeMeasureItemEnableList.Add(NewProTypeMeasureItemsEnable);
                    }
                }
            }
            catch(Exception ex)
            {

            }
        }
        private static ProductTypeMeasureItemEnable NewDefaultProTypeMeasureItemEnable (string Name, List<string> defaultMeasureItems)
        {
            ProductTypeMeasureItemEnable productTypeMeasureItemEnable = new ProductTypeMeasureItemEnable() { ProductType = Name };
            foreach(var item in defaultMeasureItems)
            {
                if(!productTypeMeasureItemEnable.MeasureItemEnableDic.ContainsKey(item))
                    productTypeMeasureItemEnable.MeasureItemEnableDic.Add(item, true);
            }
            return productTypeMeasureItemEnable;
        }


        public static void ReadCSVFile ()
        {
            try
            {
                //读取点检文件
                string[] fileNames_book = FileUtils.GetFileNames(pointCheckPath);
                foreach(string fileName in fileNames_book)
                {
                    string temp = fileName.ToLower();//统一转换为小写

                    if(temp.Contains("block_nomal.csv"))
                    {
                        BlockNomalTable = FileUtils.OpenCSV(temp);
                    }

                    if(CurProType == "Product")
                    {
                        if(temp.Contains("grr_standard_product.csv"))
                        {
                            GRRPointCheckTable = FileUtils.OpenCSV(temp);
                        }
                        if(temp.Contains("grrrange_product.csv"))
                        {
                            GRRRangeTable = FileUtils.OpenCSV(temp);
                        }
                        if(temp.Contains("grr_fai_product.txt"))//读取需要点检的尺寸
                        {
                            GRRPointCheckSize = FileUtils.ReadAllText(temp);
                        }
                    }
                }
            }
            catch
            {
                //MessageBox.Show("读取点检文件失败!");
                AppendUiLog.Log("读取点检文件失败!", LogType.Error);
            }
        }

        public static int GetRandomSeed ()
        {
            byte[] bytes = new byte[4];
            System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
            rng.GetBytes(bytes);
            return BitConverter.ToInt32(bytes, 0);
        }


        public static double GetRandom ()
        {
            Random r1 = new Random((int)(GetRandomSeed()));
            Random r2 = new Random((int)(GetRandomSeed()));
            double numb;

            do
            {
                if(r1.NextDouble() - r2.NextDouble() > 0.5 || r1.NextDouble() - r2.NextDouble() < -0.5)
                {
                    numb = r1.NextDouble() - r2.NextDouble();
                    return numb;
                }
                else
                {
                    continue;
                }
            } while(true);

        }


        public static double GetRandomDouble (double min, double max)
        {
            Random random = new Random();

            if(min > max)
            {
                throw new ArgumentException("Min value should be less than or equal to Max value.");
            }

            // 生成[0, 1)范围内的随机数
            double randomNumber = random.NextDouble();

            // 将[0, 1)范围内的随机数转换为[min, max)范围内的随机数
            double randomInRange = randomNumber * (max - min) + min;

            return randomInRange;
        }


        public static void PLCOperate_上料机 ()
        {
            if(Machine.opreateResult_Isconnect.IsSuccess)
            {
                //if (屏蔽治具1)
                //    Machine.OmronPLC.WriteBool(strAddress_ToUnloaderPLC_ASideShielded, true);
                //else
                //    Machine.OmronPLC.WriteBool(strAddress_ToUnloaderPLC_ASideShielded, false);
                //if (屏蔽治具2)
                //    Machine.OmronPLC.WriteBool(strAddress_ToUnloaderPLC_BSideShielded, true);
                //else
                //    Machine.OmronPLC.WriteBool(strAddress_ToUnloaderPLC_BSideShielded, false);
            }
        }

        /// <summary>
        /// 相机拍照
        /// </summary>
        /// <param name="FileName">算法拍照流程文件名</param>
        /// <param name="outImageName">算法输出图像名称</param>
        /// <param name="hImage">输出的图像</param>
        /// <returns></returns>
        public static bool CaptureImage (string FileName, int FixtureIndex, string outImageName, ref HImage hImage)
        {
            try
            {
                VisionPlatform.VisionManager.Engine eng2 = new VisionPlatform.VisionManager.Engine(FileName);
                eng2.SetInputNumber("FixtureIndex", FixtureIndex);
                eng2.ActionFun();
                hImage = eng2.GetOutputImage(outImageName);
            }
            catch(Exception ex)
            {
                AppendUiLog.Log($"{FileName}拍照流程异常" + ex.ToString(), LogType.Error);
                return false;
            }

            return true;
        }

        private static readonly object obj = new object();
        public static bool SaveImageLaser (HObject image, string dirPath, string ImgName)
        {
            lock(obj)
            {
                bool ret = true;
                try
                {
                    if(!FileUtils.IsExistDirectory(dirPath))
                    {
                        FileUtils.CreateDirectory(dirPath);
                    }
                    HOperatorSet.WriteImage(image, "tiff", 0, dirPath + "\\" + ImgName);// + DateTime.Now.ToString("_HH_mm_ss")
                }
                catch(Exception exc)
                {
                    ret = false;
                }
                return ret;
            }
        }

        public static void InitPlcCommunication ()
        {
            #region[PLC->PC]

            #region[安全信号]
            dic_plcComm_Bool.Add("stPLC_PC.bSafetyDoor", false);
            dic_plcComm_Bool.Add("stPLC_PC.bSafetyLightCurtain", false);
            dic_plcComm_Bool.Add("stPLC_PC.bAlarm_H", false);
            dic_plcComm_Bool.Add("stPLC_PC.bAlarm_L", false);
            dic_plcComm_Bool.Add("stPLC_PC.bSafety_LDRbt", false);
            dic_plcComm_Bool.Add("stPLC_PC.bSafety_UIdRbt", false);
            dic_plcComm_Bool.Add("stPLC_PC.Spare_BOOL[0]", false);//改下料机械手安全位

            dic_plcComm_Bool.Add("stPLC_PC.bHeartBeat", false);//改下料机械手安全位
            #endregion

            #region[产品1上下料信号]
            dic_plcComm_Bool.Add("stPLC_PC.bPut_InPos[0]", false);
            dic_plcComm_Bool.Add("stPLC_PC.bPut_Comp[0]", false);
            dic_plcComm_Bool.Add("stPLC_PC.bPick_InPos[0]", false);
            dic_plcComm_Bool.Add("stPLC_PC.bPick_Comp[0]", false);
            dic_plcComm_Bool.Add("stPLC_PC.bCCD_Req[0]", false);
            #endregion

            #region[产品2上下料信号]
            dic_plcComm_Bool.Add("stPLC_PC.bPut_InPos[1]", false);
            dic_plcComm_Bool.Add("stPLC_PC.bPut_Comp[1]", false);
            dic_plcComm_Bool.Add("stPLC_PC.bPick_InPos[1]", false);
            dic_plcComm_Bool.Add("stPLC_PC.bPick_Comp[1]", false);
            dic_plcComm_Bool.Add("stPLC_PC.bCCD_Req[1]", false);

            #endregion

            #region[上下相机拍照请求信号]
            dic_plcComm_Bool.Add("stPLC_PC.bCCD_Req_LD", false);
            dic_plcComm_Bool.Add("stPLC_PC.bCCD_Req_Uld", false);
            #endregion

            #region[预留]
            dic_plcComm_Bool.Add("stPLC_PC.bCCD_BOOL[0]", false);
            dic_plcComm_Int.Add("stPLC_PC.bCCD_INT[0]", 0);
            #endregion

            #region[设备状态]
            dic_plcComm_Int.Add("stPLC_PC.wEQPStatus", 0);
            #endregion

            #endregion
        }

        //刷新工位CT线程
        public static void ThreadLoadCt ()
        {
            while(true)
            {
                Thread.Sleep(20);
                Common.CtLook = Common.sw.Elapsed;
                Common.CtLook0 = Common.sw0.Elapsed;
                Common.CtLook1 = Common.sw1.Elapsed;
                Common.CtLook2 = Common.sw2.Elapsed;
                Common.CtLook3 = Common.sw3.Elapsed;
                Common.CtLook4 = Common.sw4.Elapsed;
                Common.CtLook5 = Common.sw5.Elapsed;
                Common.CtLook6 = Common.sw6.Elapsed;
                Common.CtLook7 = Common.sw7.Elapsed;
                Common.CtLook8 = Common.sw8.Elapsed;
                Common.CtLook9 = Common.sw9.Elapsed;
                Common.CtLook10 = Common.sw10.Elapsed;
                Common.CtLook11 = Common.sw11.Elapsed;
                Common.CtLook12 = Common.sw12.Elapsed;
            }
        }

        //和PLC信号通信的线程
        public static void ThreadMethod_ScanOmronPLC ()
        {
            try
            {
                while(MachineStatusManager.CurrentMachineStatus != MachineStatus.Quit)
                {
                    if(!是否联机上料PLC || false == Machine.opreateResult_Isconnect.IsSuccess)
                    {
                        Thread.Sleep(100);
                        continue;
                    }

                    try
                    {
                        string[] dic_Bool = dic_plcComm_Bool.Keys.ToArray<string>();
                        for(int i = 0; i < dic_Bool.Length; i++)
                        {
                            dic_plcComm_Bool[dic_Bool[i]] = Machine.OmronPLC.ReadBool(dic_Bool[i]).Content;
                        }

                        string[] dic_Int = dic_plcComm_Int.Keys.ToArray<string>();

                        for(int i = 0; i < dic_Int.Length; i++)
                        {
                            dic_plcComm_Int[dic_Int[i]] = Machine.OmronPLC.ReadInt16(dic_Int[i]).Content;
                        }
                    }
                    catch(Exception ex)
                    {
                        AppendUiLog.Log($"扫描PLC信号异常" + ex.ToString(), LogType.Error);
                    }

                    Thread.Sleep(100);
                    Application.DoEvents();
                }
            }
            catch(Exception e)
            {
                MessageBox.Show(e.ToString());
            }
        }


        public static void ThreadMethod_PLCHeart ()
        {
            while(true)
            {
                if(Machine.opreateResult_Isconnect.IsSuccess)
                {
                    Frm_Main.Instance.Invoke(new Action(() =>
                    {
                        Frm_Main.Instance.label3.Text = "PLC连接成功";
                        Frm_Main.Instance.label3.BackColor = Color.Green;
                    }));


                    Machine.OmronPLC.Write("stPC_PLC.bHeartBeat", true);
                    Thread.Sleep(1000);
                    Machine.OmronPLC.Write("stPC_PLC.bHeartBeat", false);
                    Thread.Sleep(1000);
                }
                else
                {
                    Frm_Main.Instance.Invoke(new Action(() =>
                    {
                        Frm_Main.Instance.label3.Text = "PLC连接失败";
                        Frm_Main.Instance.label3.BackColor = Color.Red;
                    }));

                }
                Thread.Sleep(10);
            }

        }


        public static void ThreadMethod_PointCheck ()
        {
            //while (true)
            //{
            //    if (Common.pointCheck == true && 治具1点检)
            //    {
            //        Common.屏蔽治具2 = true;
            //    }
            //    if (Common.pointCheck == true && 治具2点检)
            //    {
            //        Common.屏蔽治具1 = true;
            //    }
            //    if (!Common.pointCheck)
            //    {
            //        Common.屏蔽治具1 = false;
            //        Common.屏蔽治具2 = false;
            //    }
            //    Thread.Sleep(10);
            //}
        }

        public static void ThreadMethod_HeartFormPLC ()
        {
            while(true)
            {
                if(Machine.opreateResult_Isconnect.IsSuccess)
                {
                    try
                    {
                        var ret_Plc = dic_plcComm_Bool["stPLC_PC.bHeartBeat"];

                        if(ret_Plc)
                        {
                            Frm_Main.Instance.Invoke(new Action(() =>
                            {
                                Frm_Main.Instance.label4.BackColor = Color.Green;
                            }));

                        }
                        else
                        {
                            Frm_Main.Instance.Invoke(new Action(() =>
                            {
                                Frm_Main.Instance.label4.BackColor = Color.Gray;
                            }));

                        }
                    }
                    catch(Exception ex)
                    {

                    }
                }
                Thread.Sleep(800);
            }


        }

        public static void SaveCsv (MeasureProduct measureProduct, string name)
        {
            MeasureSizeServices measureSizeServices = new MeasureSizeServices();
            //MeasureProduct measureProduct = new MeasureProduct();
            bool isHeader = true;

            //在输出文档的第二列增加NG/OK
            string Header = "Time,Position,Line,MeasureId,OK_NG,NG_FAI,Barcode";
            string USL = @",-,-,-,-,-,USL";
            string NOM = @",-,-,-,-,-,NOM";
            string LSL = @",-,-,-,-,-,LSL";

            MeasureSize measureSize;
            int j = 0;
            string values = "";
            //while (true)
            //{
            Thread.Sleep(2);

            try
            {
                if(measureProduct.Position == "A")
                {
                    measureProduct.Position = "0";
                }
                if(measureProduct.Position == "B")
                {
                    measureProduct.Position = "1";
                }

                //创建存数据的路径
                string CSVDataDirectory = "";
                CSVDataDirectory = Common.dataSavePath + "\\" + Common.ProjectName + "\\" + DateTime.Now.ToString("yyyy-MM") + "\\" + "Output Data" + "\\" + Common.CurProType;
                if(!Directory.Exists(CSVDataDirectory))
                {
                    Directory.CreateDirectory(CSVDataDirectory);
                }
                string fullPath = CSVDataDirectory + @"\" + "Out" + DateTime.Now.ToString("_yyyy-MM-dd") + ".csv";//@"\"

                if(!File.Exists(fullPath))
                {
                    isHeader = true;
                    Header = "Time,Position,Line,MeasureId,OK_NG,NG_FAI,Barcode";
                    USL = @",-,-,-,-,-,USL";
                    NOM = @",-,-,-,-,-,NOM";
                    LSL = @",-,-,-,-,-,LSL";
                }
                foreach(var dataItem in measureProduct.MeasureData)
                {
                    measureSize = new MeasureSize();
                    //假设是block   
                    if(measureProduct.whichBlock == 0)
                    {
                        measureSize = measureSizeServices.GetModelByProjectNameAndSizeName("MIN", dataItem.Name);
                    }
                    if(measureProduct.whichBlock == 1)
                    {
                        measureSize = measureSizeServices.GetModelByProjectNameAndSizeName("MID", dataItem.Name);
                    }
                    if(measureProduct.whichBlock == 2)
                    {
                        measureSize = measureSizeServices.GetModelByProjectNameAndSizeName("MAX", dataItem.Name);
                    }
                    if(measureProduct.whichBlock == -1)
                    {
                        measureSize = measureSizeServices.GetModelByProjectNameAndSizeName("ACMT", dataItem.Name);
                    }

                    if(measureSize == null)
                    {
                        continue;//如果该工程下没有这个尺寸，放弃保存
                    }
                    if(measureSize.IsShow == false)
                        continue;//如果该尺寸号不需要显示，放弃保存

                    //保存到数据到CSV中  表头
                    values += string.IsNullOrEmpty(values) ? dataItem.Value.ToString("0.0000") : ("," + dataItem.Value.ToString("0.0000"));

                    if(isHeader == true)
                    {
                        Header += "," + measureSize.SizeName;
                        USL += "," + measureSize.UpperDeviation;//+ "TOL+"
                        NOM += "," + measureSize.NormValue;
                        LSL += "," + (measureSize.LowerDeviation < 0.0000001 ? "0" : ("-" + measureSize.LowerDeviation).ToString());//+ "TOL-"
                    }
                }

                string str = string.Empty;
                str += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ",";
                str += measureProduct.Position + ",";
                str += Common.Line + ",";
                j++;
                str += j.ToString() + ",";
                str += measureProduct.OK_NG + ",";
                str += measureProduct.NG_FAI + ",";
                if(measureProduct.SN == "")
                {
                    measureProduct.SN = "Test";
                }
                str += name;
                values = str + "," + values;

                if(!File.Exists(fullPath) && isHeader == true)
                {
                    FileUtils.AppendText(fullPath, Header + "\r\n");
                    FileUtils.AppendText(fullPath, USL + "\r\n");
                    FileUtils.AppendText(fullPath, NOM + "\r\n");
                    FileUtils.AppendText(fullPath, LSL + "\r\n");
                }
                isHeader = false;
                FileUtils.AppendText(fullPath, values + "\r\n");
            }
            catch(Exception ex)
            {
                Common.AppendUiLog.Log("保存CSV数据异常!" + ex.ToString(), LogType.Error);
            }

            //}
        }
    }
}

